some %x -> %p fixes
[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 INT 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 struct __attribute__((packed)) {
324 USHORT Limit;
325 ULONG Base;
326 } Idtr;
327 UCHAR Mem[2];
328 INT IntVect;
329 ULONG IntDesc[2];
330 ULONG_PTR TargetEip;
331
332 /* Read memory */
333 if (!NT_SUCCESS(KdbpSafeReadMemory(Mem, (PVOID)Eip, sizeof (Mem))))
334 {
335 /*KdbpPrint("Couldn't access memory at 0x%p\n", Eip);*/
336 return FALSE;
337 }
338
339 /* Check for INT instruction */
340 /* FIXME: Check for iret */
341 if (Mem[0] == 0xcc)
342 IntVect = 3;
343 else if (Mem[0] == 0xcd)
344 IntVect = Mem[1];
345 else if (Mem[0] == 0xce && KdbCurrentTrapFrame->Tf.Eflags & (1<<11)) /* 1 << 11 is the overflow flag */
346 IntVect = 4;
347 else
348 return FALSE;
349
350 if (IntVect < 32) /* We should be informed about interrupts < 32 by the kernel, no need to breakpoint them */
351 {
352 return FALSE;
353 }
354
355 /* Read the interrupt descriptor table register */
356 asm volatile("sidt %0" : : "m"(Idtr));
357 if (IntVect >= (Idtr.Limit + 1) / 8)
358 {
359 /*KdbpPrint("IDT does not contain interrupt vector %d\n.", IntVect);*/
360 return TRUE;
361 }
362
363 /* Get the interrupt descriptor */
364 if (!NT_SUCCESS(KdbpSafeReadMemory(IntDesc, (PVOID)(Idtr.Base + (IntVect * 8)), sizeof (IntDesc))))
365 {
366 /*KdbpPrint("Couldn't access memory at 0x%p\n", (ULONG_PTR)Idtr.Base + (IntVect * 8));*/
367 return FALSE;
368 }
369
370 /* Check descriptor and get target eip (16 bit interrupt/trap gates not supported) */
371 if ((IntDesc[1] & (1 << 15)) == 0) /* not present */
372 {
373 return FALSE;
374 }
375 if ((IntDesc[1] & 0x1f00) == 0x0500) /* Task gate */
376 {
377 /* FIXME: Task gates not supported */
378 return FALSE;
379 }
380 else if (((IntDesc[1] & 0x1fe0) == 0x0e00) || /* 32 bit Interrupt gate */
381 ((IntDesc[1] & 0x1fe0) == 0x0f00)) /* 32 bit Trap gate */
382 {
383 /* FIXME: Should the segment selector of the interrupt gate be checked? */
384 TargetEip = (IntDesc[1] & 0xffff0000) | (IntDesc[0] & 0x0000ffff);
385 }
386 else
387 {
388 return FALSE;
389 }
390
391 /* Insert breakpoint */
392 if (!NT_SUCCESS(KdbpInsertBreakPoint(TargetEip, KdbBreakPointTemporary, 0, 0, NULL, FALSE, NULL)))
393 return FALSE;
394
395 return TRUE;
396 }
397
398 /*!\brief Gets the number of the next breakpoint >= Start.
399 *
400 * \param Start Breakpoint number to start searching at. -1 if no more breakpoints are found.
401 *
402 * \returns Breakpoint number (-1 if no more breakpoints are found)
403 */
404 LONG
405 KdbpGetNextBreakPointNr(
406 IN ULONG Start OPTIONAL)
407 {
408 for (; Start < RTL_NUMBER_OF(KdbBreakPoints); Start++)
409 {
410 if (KdbBreakPoints[Start].Type != KdbBreakPointNone)
411 return Start;
412 }
413 return -1;
414 }
415
416 /*!\brief Returns information of the specified breakpoint.
417 *
418 * \param BreakPointNr Number of the breakpoint to return information of.
419 * \param Address Receives the address of the breakpoint.
420 * \param Type Receives the type of the breakpoint (hardware or software)
421 * \param Size Size - for memory breakpoints.
422 * \param AccessType Access type - for hardware breakpoints.
423 * \param DebugReg Debug register - for enabled hardware breakpoints.
424 * \param Enabled Whether the breakpoint is enabled or not.
425 * \param Process The owning process of the breakpoint.
426 * \param ConditionExpression The expression which was given as condition for the bp.
427 *
428 * \returns NULL on failure, pointer to a KDB_BREAKPOINT struct on success.
429 */
430 BOOLEAN
431 KdbpGetBreakPointInfo(
432 IN ULONG BreakPointNr,
433 OUT ULONG_PTR *Address OPTIONAL,
434 OUT KDB_BREAKPOINT_TYPE *Type OPTIONAL,
435 OUT UCHAR *Size OPTIONAL,
436 OUT KDB_ACCESS_TYPE *AccessType OPTIONAL,
437 OUT UCHAR *DebugReg OPTIONAL,
438 OUT BOOLEAN *Enabled OPTIONAL,
439 OUT BOOLEAN *Global OPTIONAL,
440 OUT PEPROCESS *Process OPTIONAL,
441 OUT PCHAR *ConditionExpression OPTIONAL)
442 {
443 PKDB_BREAKPOINT bp;
444
445 if (BreakPointNr >= RTL_NUMBER_OF(KdbBreakPoints) ||
446 KdbBreakPoints[BreakPointNr].Type == KdbBreakPointNone)
447 {
448 return FALSE;
449 }
450
451 bp = KdbBreakPoints + BreakPointNr;
452 if (Address != NULL)
453 *Address = bp->Address;
454 if (Type != NULL)
455 *Type = bp->Type;
456 if (bp->Type == KdbBreakPointHardware)
457 {
458 if (Size != NULL)
459 *Size = bp->Data.Hw.Size;
460 if (AccessType != NULL)
461 *AccessType = bp->Data.Hw.AccessType;
462 if (DebugReg != NULL && bp->Enabled)
463 *DebugReg = bp->Data.Hw.DebugReg;
464 }
465 if (Enabled != NULL)
466 *Enabled = bp->Enabled;
467 if (Global != NULL)
468 *Global = bp->Global;
469 if (Process != NULL)
470 *Process = bp->Process;
471 if (ConditionExpression != NULL)
472 *ConditionExpression = bp->ConditionExpression;
473
474 return TRUE;
475 }
476
477 /*!\brief Inserts a breakpoint into the breakpoint array.
478 *
479 * The \a Process of the breakpoint is set to \a KdbCurrentProcess
480 *
481 * \param Address Address at which to set the breakpoint.
482 * \param Type Type of breakpoint (hardware or software)
483 * \param Size Size of breakpoint (for hardware/memory breakpoints)
484 * \param AccessType Access type (for hardware breakpoins)
485 * \param ConditionExpression Expression which must evaluate to true for conditional breakpoints.
486 * \param Global Wether the breakpoint is global or local to a process.
487 * \param BreakPointNumber Receives the breakpoint number on success
488 *
489 * \returns NTSTATUS
490 */
491 NTSTATUS
492 KdbpInsertBreakPoint(
493 IN ULONG_PTR Address,
494 IN KDB_BREAKPOINT_TYPE Type,
495 IN UCHAR Size OPTIONAL,
496 IN KDB_ACCESS_TYPE AccessType OPTIONAL,
497 IN PCHAR ConditionExpression OPTIONAL,
498 IN BOOLEAN Global,
499 OUT PULONG BreakPointNumber OPTIONAL)
500 {
501 LONG i;
502 PVOID Condition;
503 PCHAR ConditionExpressionDup;
504 LONG ErrOffset;
505 CHAR ErrMsg[128];
506
507 ASSERT(Type != KdbBreakPointNone);
508
509 if (Type == KdbBreakPointHardware)
510 {
511 if ((Address % Size) != 0)
512 {
513 KdbpPrint("Address (0x%p) must be aligned to a multiple of the size (%d)\n", Address, Size);
514 return STATUS_UNSUCCESSFUL;
515 }
516 if (AccessType == KdbAccessExec && Size != 1)
517 {
518 KdbpPrint("Size must be 1 for execution breakpoints.\n");
519 return STATUS_UNSUCCESSFUL;
520 }
521 }
522
523 if (KdbBreakPointCount == KDB_MAXIMUM_BREAKPOINT_COUNT)
524 {
525 return STATUS_UNSUCCESSFUL;
526 }
527
528 /* Parse conditon expression string and duplicate it */
529 if (ConditionExpression != NULL)
530 {
531 Condition = KdbpRpnParseExpression(ConditionExpression, &ErrOffset, ErrMsg);
532 if (Condition == NULL)
533 {
534 if (ErrOffset >= 0)
535 KdbpPrint("Couldn't parse expression: %s at character %d\n", ErrMsg, ErrOffset);
536 else
537 KdbpPrint("Couldn't parse expression: %s", ErrMsg);
538 return STATUS_UNSUCCESSFUL;
539 }
540
541 i = strlen(ConditionExpression) + 1;
542 ConditionExpressionDup = ExAllocatePoolWithTag(NonPagedPool, i, TAG_KDBG);
543 RtlCopyMemory(ConditionExpressionDup, ConditionExpression, i);
544
545 }
546 else
547 {
548 Condition = NULL;
549 ConditionExpressionDup = NULL;
550 }
551
552 /* Find unused breakpoint */
553 if (Type == KdbBreakPointTemporary)
554 {
555 for (i = RTL_NUMBER_OF(KdbBreakPoints) - 1; i >= 0; i--)
556 {
557 if (KdbBreakPoints[i].Type == KdbBreakPointNone)
558 break;
559 }
560 }
561 else
562 {
563 for (i = 0; i < RTL_NUMBER_OF(KdbBreakPoints); i++)
564 {
565 if (KdbBreakPoints[i].Type == KdbBreakPointNone)
566 break;
567 }
568 }
569 ASSERT(i < RTL_NUMBER_OF(KdbBreakPoints));
570
571 /* Set the breakpoint */
572 ASSERT(KdbCurrentProcess != NULL);
573 KdbBreakPoints[i].Type = Type;
574 KdbBreakPoints[i].Address = Address;
575 KdbBreakPoints[i].Enabled = FALSE;
576 KdbBreakPoints[i].Global = Global;
577 KdbBreakPoints[i].Process = KdbCurrentProcess;
578 KdbBreakPoints[i].ConditionExpression = ConditionExpressionDup;
579 KdbBreakPoints[i].Condition = Condition;
580 if (Type == KdbBreakPointHardware)
581 {
582
583 KdbBreakPoints[i].Data.Hw.Size = Size;
584 KdbBreakPoints[i].Data.Hw.AccessType = AccessType;
585 }
586 KdbBreakPointCount++;
587
588 if (Type != KdbBreakPointTemporary)
589 KdbpPrint("Breakpoint %d inserted.\n", i);
590
591 /* Try to enable the breakpoint */
592 KdbpEnableBreakPoint(i, NULL);
593
594 /* Return the breakpoint number */
595 if (BreakPointNumber != NULL)
596 *BreakPointNumber = i;
597
598 return STATUS_SUCCESS;
599 }
600
601 /*!\brief Deletes a breakpoint
602 *
603 * \param BreakPointNr Number of the breakpoint to delete. Can be -1
604 * \param BreakPoint Breakpoint to delete. Can be NULL.
605 *
606 * \retval TRUE Success.
607 * \retval FALSE Failure (invalid breakpoint number)
608 */
609 BOOLEAN
610 KdbpDeleteBreakPoint(
611 IN LONG BreakPointNr OPTIONAL,
612 IN OUT PKDB_BREAKPOINT BreakPoint OPTIONAL)
613 {
614 if (BreakPointNr < 0)
615 {
616 ASSERT(BreakPoint != NULL);
617 BreakPointNr = BreakPoint - KdbBreakPoints;
618 }
619 if (BreakPointNr < 0 || BreakPointNr >= KDB_MAXIMUM_BREAKPOINT_COUNT)
620 {
621 KdbpPrint("Invalid breakpoint: %d\n", BreakPointNr);
622 return FALSE;
623 }
624 if (BreakPoint == NULL)
625 {
626 BreakPoint = KdbBreakPoints + BreakPointNr;
627 }
628 if (BreakPoint->Type == KdbBreakPointNone)
629 {
630 KdbpPrint("Invalid breakpoint: %d\n", BreakPointNr);
631 return FALSE;
632 }
633
634 if (BreakPoint->Enabled &&
635 !KdbpDisableBreakPoint(-1, BreakPoint))
636 return FALSE;
637
638 if (BreakPoint->Type != KdbBreakPointTemporary)
639 KdbpPrint("Breakpoint %d deleted.\n", BreakPointNr);
640 BreakPoint->Type = KdbBreakPointNone;
641 KdbBreakPointCount--;
642
643 return TRUE;
644 }
645
646 /*!\brief Checks if the breakpoint was set by the debugger
647 *
648 * Tries to find a breakpoint in the breakpoint array which caused
649 * the debug exception to happen.
650 *
651 * \param ExpNr Exception Number (1 or 3)
652 * \param TrapFrame Exception trapframe
653 *
654 * \returns Breakpoint number, -1 on error.
655 */
656 STATIC LONG
657 KdbpIsBreakPointOurs(
658 IN ULONG ExpNr,
659 IN PKTRAP_FRAME TrapFrame)
660 {
661 INT i;
662 ASSERT(ExpNr == 1 || ExpNr == 3);
663
664 if (ExpNr == 3) /* Software interrupt */
665 {
666 ULONG_PTR BpEip = (ULONG_PTR)TrapFrame->Eip - 1; /* Get EIP of INT3 instruction */
667 for (i = 0; i < KdbSwBreakPointCount; i++)
668 {
669 ASSERT((KdbSwBreakPoints[i]->Type == KdbBreakPointSoftware ||
670 KdbSwBreakPoints[i]->Type == KdbBreakPointTemporary));
671 ASSERT(KdbSwBreakPoints[i]->Enabled);
672 if (KdbSwBreakPoints[i]->Address == BpEip)
673 {
674 return KdbSwBreakPoints[i] - KdbBreakPoints;
675 }
676 }
677 }
678 else if (ExpNr == 1) /* Hardware interrupt */
679 {
680 UCHAR DebugReg;
681 for (i = 0; i < KdbHwBreakPointCount; i++)
682 {
683 ASSERT(KdbHwBreakPoints[i]->Type == KdbBreakPointHardware &&
684 KdbHwBreakPoints[i]->Enabled);
685 DebugReg = KdbHwBreakPoints[i]->Data.Hw.DebugReg;
686 if ((TrapFrame->Dr6 & (1 << DebugReg)) != 0)
687 {
688 return KdbHwBreakPoints[i] - KdbBreakPoints;
689 }
690 }
691 }
692
693 return -1;
694 }
695
696 /*!\brief Enables a breakpoint.
697 *
698 * \param BreakPointNr Number of the breakpoint to enable Can be -1.
699 * \param BreakPoint Breakpoint to enable. Can be NULL.
700 *
701 * \retval TRUE Success.
702 * \retval FALSE Failure.
703 *
704 * \sa KdbpDisableBreakPoint
705 */
706 BOOLEAN
707 KdbpEnableBreakPoint(
708 IN LONG BreakPointNr OPTIONAL,
709 IN OUT PKDB_BREAKPOINT BreakPoint OPTIONAL)
710 {
711 NTSTATUS Status;
712 INT i;
713 ULONG ul;
714
715 if (BreakPointNr < 0)
716 {
717 ASSERT(BreakPoint != NULL);
718 BreakPointNr = BreakPoint - KdbBreakPoints;
719 }
720 if (BreakPointNr < 0 || BreakPointNr >= KDB_MAXIMUM_BREAKPOINT_COUNT)
721 {
722 KdbpPrint("Invalid breakpoint: %d\n", BreakPointNr);
723 return FALSE;
724 }
725 if (BreakPoint == NULL)
726 {
727 BreakPoint = KdbBreakPoints + BreakPointNr;
728 }
729 if (BreakPoint->Type == KdbBreakPointNone)
730 {
731 KdbpPrint("Invalid breakpoint: %d\n", BreakPointNr);
732 return FALSE;
733 }
734
735 if (BreakPoint->Enabled == TRUE)
736 {
737 KdbpPrint("Breakpoint %d is already enabled.\n", BreakPointNr);
738 return TRUE;
739 }
740
741 if (BreakPoint->Type == KdbBreakPointSoftware ||
742 BreakPoint->Type == KdbBreakPointTemporary)
743 {
744 if (KdbSwBreakPointCount >= KDB_MAXIMUM_SW_BREAKPOINT_COUNT)
745 {
746 KdbpPrint("Maximum number of SW breakpoints (%d) used. "
747 "Disable another breakpoint in order to enable this one.\n",
748 KDB_MAXIMUM_SW_BREAKPOINT_COUNT);
749 return FALSE;
750 }
751 Status = KdbpOverwriteInstruction(BreakPoint->Process, BreakPoint->Address,
752 0xCC, &BreakPoint->Data.SavedInstruction);
753 if (!NT_SUCCESS(Status))
754 {
755 KdbpPrint("Couldn't access memory at 0x%p\n", BreakPoint->Address);
756 return FALSE;
757 }
758 KdbSwBreakPoints[KdbSwBreakPointCount++] = BreakPoint;
759 }
760 else
761 {
762 if (BreakPoint->Data.Hw.AccessType == KdbAccessExec)
763 ASSERT(BreakPoint->Data.Hw.Size == 1);
764 ASSERT((BreakPoint->Address % BreakPoint->Data.Hw.Size) == 0);
765 if (KdbHwBreakPointCount >= KDB_MAXIMUM_HW_BREAKPOINT_COUNT)
766 {
767 KdbpPrint("Maximum number of HW breakpoints (%d) already used. "
768 "Disable another breakpoint in order to enable this one.\n",
769 KDB_MAXIMUM_HW_BREAKPOINT_COUNT);
770 return FALSE;
771 }
772
773 /* Find unused hw breakpoint */
774 ASSERT(KDB_MAXIMUM_HW_BREAKPOINT_COUNT == 4);
775 for (i = 0; i < KDB_MAXIMUM_HW_BREAKPOINT_COUNT; i++)
776 {
777 if ((KdbTrapFrame.Tf.Dr7 & (0x3 << (i * 2))) == 0)
778 break;
779 }
780 ASSERT(i < KDB_MAXIMUM_HW_BREAKPOINT_COUNT);
781
782 /* Set the breakpoint address. */
783 switch (i)
784 {
785 case 0:
786 KdbTrapFrame.Tf.Dr0 = BreakPoint->Address;
787 break;
788 case 1:
789 KdbTrapFrame.Tf.Dr1 = BreakPoint->Address;
790 break;
791 case 2:
792 KdbTrapFrame.Tf.Dr2 = BreakPoint->Address;
793 break;
794 case 3:
795 KdbTrapFrame.Tf.Dr3 = BreakPoint->Address;
796 break;
797 }
798
799 /* Enable the global breakpoint */
800 KdbTrapFrame.Tf.Dr7 |= (0x2 << (i * 2));
801
802 /* Enable the exact match bits. */
803 KdbTrapFrame.Tf.Dr7 |= 0x00000300;
804
805 /* Clear existing state. */
806 KdbTrapFrame.Tf.Dr7 &= ~(0xF << (16 + (i * 4)));
807
808 /* Set the breakpoint type. */
809 switch (BreakPoint->Data.Hw.AccessType)
810 {
811 case KdbAccessExec:
812 ul = 0;
813 break;
814 case KdbAccessWrite:
815 ul = 1;
816 break;
817 case KdbAccessRead:
818 case KdbAccessReadWrite:
819 ul = 3;
820 break;
821 default:
822 ASSERT(0);
823 return TRUE;
824 break;
825 }
826 KdbTrapFrame.Tf.Dr7 |= (ul << (16 + (i * 4)));
827
828 /* Set the breakpoint length. */
829 KdbTrapFrame.Tf.Dr7 |= ((BreakPoint->Data.Hw.Size - 1) << (18 + (i * 4)));
830
831 /* Update KdbCurrentTrapFrame - values are taken from there by the CLI */
832 if (&KdbTrapFrame != KdbCurrentTrapFrame)
833 {
834 KdbCurrentTrapFrame->Tf.Dr0 = KdbTrapFrame.Tf.Dr0;
835 KdbCurrentTrapFrame->Tf.Dr1 = KdbTrapFrame.Tf.Dr1;
836 KdbCurrentTrapFrame->Tf.Dr2 = KdbTrapFrame.Tf.Dr2;
837 KdbCurrentTrapFrame->Tf.Dr3 = KdbTrapFrame.Tf.Dr3;
838 KdbCurrentTrapFrame->Tf.Dr6 = KdbTrapFrame.Tf.Dr6;
839 KdbCurrentTrapFrame->Tf.Dr7 = KdbTrapFrame.Tf.Dr7;
840 }
841
842 BreakPoint->Data.Hw.DebugReg = i;
843 KdbHwBreakPoints[KdbHwBreakPointCount++] = BreakPoint;
844 }
845
846 BreakPoint->Enabled = TRUE;
847 if (BreakPoint->Type != KdbBreakPointTemporary)
848 KdbpPrint("Breakpoint %d enabled.\n", BreakPointNr);
849 return TRUE;
850 }
851
852 /*!\brief Disables a breakpoint.
853 *
854 * \param BreakPointNr Number of the breakpoint to disable. Can be -1
855 * \param BreakPoint Breakpoint to disable. Can be NULL.
856 *
857 * \retval TRUE Success.
858 * \retval FALSE Failure.
859 *
860 * \sa KdbpEnableBreakPoint
861 */
862 BOOLEAN
863 KdbpDisableBreakPoint(
864 IN LONG BreakPointNr OPTIONAL,
865 IN OUT PKDB_BREAKPOINT BreakPoint OPTIONAL)
866 {
867 INT i;
868 NTSTATUS Status;
869
870 if (BreakPointNr < 0)
871 {
872 ASSERT(BreakPoint != NULL);
873 BreakPointNr = BreakPoint - KdbBreakPoints;
874 }
875 if (BreakPointNr < 0 || BreakPointNr >= KDB_MAXIMUM_BREAKPOINT_COUNT)
876 {
877 KdbpPrint("Invalid breakpoint: %d\n", BreakPointNr);
878 return FALSE;
879 }
880 if (BreakPoint == NULL)
881 {
882 BreakPoint = KdbBreakPoints + BreakPointNr;
883 }
884 if (BreakPoint->Type == KdbBreakPointNone)
885 {
886 KdbpPrint("Invalid breakpoint: %d\n", BreakPointNr);
887 return FALSE;
888 }
889
890 if (BreakPoint->Enabled == FALSE)
891 {
892 KdbpPrint("Breakpoint %d is not enabled.\n", BreakPointNr);
893 return TRUE;
894 }
895
896 if (BreakPoint->Type == KdbBreakPointSoftware ||
897 BreakPoint->Type == KdbBreakPointTemporary)
898 {
899 ASSERT(KdbSwBreakPointCount > 0);
900 Status = KdbpOverwriteInstruction(BreakPoint->Process, BreakPoint->Address,
901 BreakPoint->Data.SavedInstruction, NULL);
902 if (!NT_SUCCESS(Status))
903 {
904 KdbpPrint("Couldn't restore original instruction.\n");
905 return FALSE;
906 }
907
908 for (i = 0; i < KdbSwBreakPointCount; i++)
909 {
910 if (KdbSwBreakPoints[i] == BreakPoint)
911 {
912 KdbSwBreakPoints[i] = KdbSwBreakPoints[--KdbSwBreakPointCount];
913 i = -1; /* if the last breakpoint is disabled dont break with i >= KdbSwBreakPointCount */
914 break;
915 }
916 }
917 if (i != -1) /* not found */
918 ASSERT(0);
919 }
920 else
921 {
922 ASSERT(BreakPoint->Type == KdbBreakPointHardware);
923
924 /* Clear the breakpoint. */
925 KdbTrapFrame.Tf.Dr7 &= ~(0x3 << (BreakPoint->Data.Hw.DebugReg * 2));
926 if ((KdbTrapFrame.Tf.Dr7 & 0xFF) == 0)
927 {
928 /*
929 * If no breakpoints are enabled then clear the exact match flags.
930 */
931 KdbTrapFrame.Tf.Dr7 &= 0xFFFFFCFF;
932 }
933
934 for (i = 0; i < KdbHwBreakPointCount; i++)
935 {
936 if (KdbHwBreakPoints[i] == BreakPoint)
937 {
938 KdbHwBreakPoints[i] = KdbHwBreakPoints[--KdbHwBreakPointCount];
939 i = -1; /* if the last breakpoint is disabled dont break with i >= KdbHwBreakPointCount */
940 break;
941 }
942 }
943 if (i != -1) /* not found */
944 ASSERT(0);
945 }
946
947 BreakPoint->Enabled = FALSE;
948 if (BreakPoint->Type != KdbBreakPointTemporary)
949 KdbpPrint("Breakpoint %d disabled.\n", BreakPointNr);
950 return TRUE;
951 }
952
953 /*!\brief Gets the first or last chance enter-condition for exception nr. \a ExceptionNr
954 *
955 * \param ExceptionNr Number of the exception to get condition of.
956 * \param FirstChance Whether to get first or last chance condition.
957 * \param Condition Receives the condition setting.
958 *
959 * \retval TRUE Success.
960 * \retval FALSE Failure (invalid exception nr)
961 */
962 BOOLEAN
963 KdbpGetEnterCondition(
964 IN LONG ExceptionNr,
965 IN BOOLEAN FirstChance,
966 OUT KDB_ENTER_CONDITION *Condition)
967 {
968 if (ExceptionNr >= RTL_NUMBER_OF(KdbEnterConditions))
969 return FALSE;
970
971 *Condition = KdbEnterConditions[ExceptionNr][FirstChance ? 0 : 1];
972 return TRUE;
973 }
974
975 /*!\brief Sets the first or last chance enter-condition for exception nr. \a ExceptionNr
976 *
977 * \param ExceptionNr Number of the exception to set condition of (-1 for all)
978 * \param FirstChance Whether to set first or last chance condition.
979 * \param Condition The new condition setting.
980 *
981 * \retval TRUE Success.
982 * \retval FALSE Failure (invalid exception nr)
983 */
984 BOOLEAN
985 KdbpSetEnterCondition(
986 IN LONG ExceptionNr,
987 IN BOOLEAN FirstChance,
988 IN KDB_ENTER_CONDITION Condition)
989 {
990 if (ExceptionNr < 0)
991 {
992 for (ExceptionNr = 0; ExceptionNr < RTL_NUMBER_OF(KdbEnterConditions); ExceptionNr++)
993 {
994 if (ExceptionNr == 1 || ExceptionNr == 8 ||
995 ExceptionNr == 9 || ExceptionNr == 15) /* Reserved exceptions */
996 {
997 continue;
998 }
999 KdbEnterConditions[ExceptionNr][FirstChance ? 0 : 1] = Condition;
1000 }
1001 }
1002 else
1003 {
1004 if (ExceptionNr >= RTL_NUMBER_OF(KdbEnterConditions) ||
1005 ExceptionNr == 1 || ExceptionNr == 8 || /* Do not allow changing of the debug */
1006 ExceptionNr == 9 || ExceptionNr == 15) /* trap or reserved exceptions */
1007 {
1008 return FALSE;
1009 }
1010 KdbEnterConditions[ExceptionNr][FirstChance ? 0 : 1] = Condition;
1011 }
1012 return TRUE;
1013 }
1014
1015 /*!\brief Switches to another thread context
1016 *
1017 * \param ThreadId Id of the thread to switch to.
1018 *
1019 * \retval TRUE Success.
1020 * \retval FALSE Failure (i.e. invalid thread id)
1021 */
1022 BOOLEAN
1023 KdbpAttachToThread(
1024 PVOID ThreadId)
1025 {
1026 PETHREAD Thread = NULL;
1027 PEPROCESS Process;
1028
1029 /* Get a pointer to the thread */
1030 if (!NT_SUCCESS(PsLookupThreadByThreadId(ThreadId, &Thread)))
1031 {
1032 KdbpPrint("Invalid thread id: 0x%08x\n", (UINT)ThreadId);
1033 return FALSE;
1034 }
1035 Process = Thread->ThreadsProcess;
1036
1037 if (KeIsExecutingDpc() && Process != KdbCurrentProcess)
1038 {
1039 KdbpPrint("Cannot attach to thread within another process while executing a DPC.\n");
1040 return FALSE;
1041 }
1042
1043 /* Save the current thread's context (if we previously attached to a thread) */
1044 if (KdbCurrentThread != KdbOriginalThread)
1045 {
1046 ASSERT(KdbCurrentTrapFrame == &KdbThreadTrapFrame);
1047 KdbpKdbTrapFrameToTrapFrame(KdbCurrentTrapFrame, KdbCurrentThread->Tcb.TrapFrame);
1048 }
1049 else
1050 {
1051 ASSERT(KdbCurrentTrapFrame == &KdbTrapFrame);
1052 }
1053
1054 /* Switch to the thread's context */
1055 if (Thread != KdbOriginalThread)
1056 {
1057 if (Thread->Tcb.TrapFrame == NULL)
1058 {
1059 KdbpPrint("Threads TrapFrame is NULL! Cannot attach.\n");
1060 return FALSE;
1061 }
1062 KdbpTrapFrameToKdbTrapFrame(Thread->Tcb.TrapFrame, &KdbThreadTrapFrame);
1063 KdbCurrentTrapFrame = &KdbThreadTrapFrame;
1064 }
1065 else /* Switching back to original thread */
1066 {
1067 KdbCurrentTrapFrame = &KdbTrapFrame;
1068 }
1069 KdbCurrentThread = Thread;
1070
1071 /* Attach to the thread's process */
1072 ASSERT(KdbCurrentProcess == PsGetCurrentProcess());
1073 if (KdbCurrentProcess != Process)
1074 {
1075 if (KdbCurrentProcess != KdbOriginalProcess) /* detach from previously attached process */
1076 {
1077 KeUnstackDetachProcess(&KdbApcState);
1078 }
1079 if (KdbOriginalProcess != Process)
1080 {
1081 KeStackAttachProcess(EPROCESS_TO_KPROCESS(Process), &KdbApcState);
1082 }
1083 KdbCurrentProcess = Process;
1084 }
1085
1086 return TRUE;
1087 }
1088
1089 /*!\brief Switches to another process/thread context
1090 *
1091 * This function switches to the first thread in the specified process.
1092 *
1093 * \param ProcessId Id of the process to switch to.
1094 *
1095 * \retval TRUE Success.
1096 * \retval FALSE Failure (i.e. invalid process id)
1097 */
1098 BOOLEAN
1099 KdbpAttachToProcess(
1100 PVOID ProcessId)
1101 {
1102 PEPROCESS Process = NULL;
1103 PETHREAD Thread;
1104 PLIST_ENTRY Entry;
1105
1106 /* Get a pointer to the process */
1107 if (!NT_SUCCESS(PsLookupProcessByProcessId(ProcessId, &Process)))
1108 {
1109 KdbpPrint("Invalid process id: 0x%08x\n", (UINT)ProcessId);
1110 return FALSE;
1111 }
1112
1113 Entry = Process->ThreadListHead.Flink;
1114 if (Entry == &KdbCurrentProcess->ThreadListHead)
1115 {
1116 KdbpPrint("No threads in process 0x%08x, cannot attach to process!\n", (UINT)ProcessId);
1117 return FALSE;
1118 }
1119
1120 Thread = CONTAINING_RECORD(Entry, ETHREAD, ThreadListEntry);
1121
1122 return KdbpAttachToThread(Thread->Cid.UniqueThread);
1123 }
1124
1125 /*!\brief Calls the main loop ...
1126 */
1127 STATIC VOID
1128 KdbpCallMainLoop()
1129 {
1130 KdbpCliMainLoop(KdbEnteredOnSingleStep);
1131 }
1132
1133 /*!\brief Internal function to enter KDB.
1134 *
1135 * Disables interrupts, releases display ownership, ...
1136 */
1137 STATIC VOID
1138 KdbpInternalEnter()
1139 {
1140 PETHREAD Thread;
1141 PVOID SavedInitialStack, SavedStackBase, SavedKernelStack;
1142 ULONG SavedStackLimit;
1143
1144 KbdDisableMouse();
1145 if (KdpDebugMode.Screen)
1146 {
1147 HalReleaseDisplayOwnership();
1148 }
1149
1150 /* Call the interface's main loop on a different stack */
1151 Thread = PsGetCurrentThread();
1152 SavedInitialStack = Thread->Tcb.InitialStack;
1153 SavedStackBase = Thread->Tcb.StackBase;
1154 SavedStackLimit = Thread->Tcb.StackLimit;
1155 SavedKernelStack = Thread->Tcb.KernelStack;
1156 Thread->Tcb.InitialStack = Thread->Tcb.StackBase = (char*)KdbStack + KDB_STACK_SIZE;
1157 Thread->Tcb.StackLimit = (ULONG)KdbStack;
1158 Thread->Tcb.KernelStack = (char*)KdbStack + KDB_STACK_SIZE;
1159
1160 /*KdbpPrint("Switching to KDB stack 0x%08x-0x%08x\n", Thread->Tcb.StackLimit, Thread->Tcb.StackBase);*/
1161
1162 KdbpStackSwitchAndCall(Thread->Tcb.KernelStack, KdbpCallMainLoop);
1163
1164 Thread->Tcb.InitialStack = SavedInitialStack;
1165 Thread->Tcb.StackBase = SavedStackBase;
1166 Thread->Tcb.StackLimit = SavedStackLimit;
1167 Thread->Tcb.KernelStack = SavedKernelStack;
1168 KbdEnableMouse();
1169 }
1170
1171 /*!\brief KDB Exception filter
1172 *
1173 * Called by the exception dispatcher.
1174 *
1175 * \param ExceptionRecord Unused.
1176 * \param PreviousMode UserMode if the exception was raised from umode, otherwise KernelMode.
1177 * \param Context Unused.
1178 * \param TrapFrame Exception TrapFrame.
1179 * \param FirstChance TRUE when called before exception frames were serached,
1180 * FALSE for the second call.
1181 *
1182 * \returns KD_CONTINUE_TYPE
1183 */
1184 KD_CONTINUE_TYPE
1185 KdbEnterDebuggerException(
1186 IN PEXCEPTION_RECORD ExceptionRecord OPTIONAL,
1187 IN KPROCESSOR_MODE PreviousMode,
1188 IN PCONTEXT Context OPTIONAL,
1189 IN OUT PKTRAP_FRAME TrapFrame,
1190 IN BOOLEAN FirstChance)
1191 {
1192 ULONG ExpNr = (ULONG)TrapFrame->DebugArgMark;
1193 KDB_ENTER_CONDITION EnterCondition;
1194 KD_CONTINUE_TYPE ContinueType = kdHandleException;
1195 PKDB_BREAKPOINT BreakPoint;
1196 ULONG ul;
1197 ULONGLONG ull;
1198 BOOLEAN Resume = FALSE;
1199 BOOLEAN EnterConditionMet = TRUE;
1200 ULONG OldEflags;
1201
1202 KdbCurrentProcess = PsGetCurrentProcess();
1203
1204 /* Set continue type to kdContinue for single steps and breakpoints */
1205 if (ExpNr == 1 || ExpNr == 3)
1206 ContinueType = kdContinue;
1207
1208 /* Check if we should handle the exception. */
1209 ul = min(ExpNr, RTL_NUMBER_OF(KdbEnterConditions) - 1);
1210 EnterCondition = KdbEnterConditions[ul][FirstChance ? 0 : 1];
1211 if (EnterCondition == KdbDoNotEnter ||
1212 (EnterCondition == KdbEnterFromUmode && PreviousMode != UserMode) ||
1213 (EnterCondition == KdbEnterFromKmode && PreviousMode != KernelMode))
1214 {
1215 EnterConditionMet = FALSE;
1216 }
1217
1218 /* If we stopped on one of our breakpoints then let the user know. */
1219 KdbLastBreakPointNr = -1;
1220 KdbEnteredOnSingleStep = FALSE;
1221
1222 if (FirstChance && (ExpNr == 1 || ExpNr == 3) &&
1223 (KdbLastBreakPointNr = KdbpIsBreakPointOurs(ExpNr, TrapFrame)) >= 0)
1224 {
1225 BreakPoint = KdbBreakPoints + KdbLastBreakPointNr;
1226
1227 if (ExpNr == 3)
1228 {
1229 /*
1230 * The breakpoint will point to the next instruction by default so
1231 * point it back to the start of original instruction.
1232 */
1233 TrapFrame->Eip--;
1234
1235 /*
1236 * ... and restore the original instruction.
1237 */
1238 if (!NT_SUCCESS(KdbpOverwriteInstruction(KdbCurrentProcess, BreakPoint->Address,
1239 BreakPoint->Data.SavedInstruction, NULL)))
1240 {
1241 DbgPrint("Couldn't restore original instruction after INT3! Cannot continue execution.\n");
1242 KEBUGCHECK(0);
1243 }
1244 }
1245
1246 if ((BreakPoint->Type == KdbBreakPointHardware) &&
1247 (BreakPoint->Data.Hw.AccessType == KdbAccessExec))
1248 {
1249 Resume = TRUE; /* Set the resume flag when continuing execution */
1250 }
1251
1252 /*
1253 * When a temporary breakpoint is hit we have to make sure that we are
1254 * in the same context in which it was set, otherwise it could happen
1255 * that another process/thread hits it before and it gets deleted.
1256 */
1257 else if (BreakPoint->Type == KdbBreakPointTemporary &&
1258 BreakPoint->Process == KdbCurrentProcess)
1259 {
1260 ASSERT((TrapFrame->Eflags & X86_EFLAGS_TF) == 0);
1261
1262 /*
1263 * Delete the temporary breakpoint which was used to step over or into the instruction.
1264 */
1265 KdbpDeleteBreakPoint(-1, BreakPoint);
1266
1267 if (--KdbNumSingleSteps > 0)
1268 {
1269 if ((KdbSingleStepOver && !KdbpStepOverInstruction(TrapFrame->Eip)) ||
1270 (!KdbSingleStepOver && !KdbpStepIntoInstruction(TrapFrame->Eip)))
1271 {
1272 TrapFrame->Eflags |= X86_EFLAGS_TF;
1273 }
1274 goto continue_execution; /* return */
1275 }
1276
1277 KdbEnteredOnSingleStep = TRUE;
1278 }
1279
1280 /*
1281 * If we hit a breakpoint set by the debugger we set the single step flag,
1282 * ignore the next single step and reenable the breakpoint.
1283 */
1284 else if (BreakPoint->Type == KdbBreakPointSoftware ||
1285 BreakPoint->Type == KdbBreakPointTemporary)
1286 {
1287 ASSERT(ExpNr == 3);
1288 TrapFrame->Eflags |= X86_EFLAGS_TF;
1289 KdbBreakPointToReenable = BreakPoint;
1290 }
1291
1292 /*
1293 * Make sure that the breakpoint should be triggered in this context
1294 */
1295 if (!BreakPoint->Global && BreakPoint->Process != KdbCurrentProcess)
1296 {
1297 goto continue_execution; /* return */
1298 }
1299
1300 /*
1301 * Check if the condition for the breakpoint is met.
1302 */
1303 if (BreakPoint->Condition != NULL)
1304 {
1305 /* Setup the KDB trap frame */
1306 KdbpTrapFrameToKdbTrapFrame(TrapFrame, &KdbTrapFrame);
1307
1308 ull = 0;
1309 if (!KdbpRpnEvaluateParsedExpression(BreakPoint->Condition, &KdbTrapFrame, &ull, NULL, NULL))
1310 {
1311 /* FIXME: Print warning? */
1312 }
1313 else if (ull == 0) /* condition is not met */
1314 {
1315 goto continue_execution; /* return */
1316 }
1317 }
1318
1319 if (BreakPoint->Type == KdbBreakPointSoftware)
1320 {
1321 DbgPrint("Entered debugger on breakpoint #%d: EXEC 0x%04x:0x%08x\n",
1322 KdbLastBreakPointNr, TrapFrame->Cs & 0xffff, TrapFrame->Eip);
1323 }
1324 else if (BreakPoint->Type == KdbBreakPointHardware)
1325 {
1326 DbgPrint("Entered debugger on breakpoint #%d: %s 0x%08x\n",
1327 KdbLastBreakPointNr,
1328 (BreakPoint->Data.Hw.AccessType == KdbAccessRead) ? "READ" :
1329 ((BreakPoint->Data.Hw.AccessType == KdbAccessWrite) ? "WRITE" :
1330 ((BreakPoint->Data.Hw.AccessType == KdbAccessReadWrite) ? "RDWR" : "EXEC")
1331 ),
1332 BreakPoint->Address
1333 );
1334
1335 }
1336 }
1337 else if (ExpNr == 1)
1338 {
1339 /* Silently ignore a debugger initiated single step. */
1340 if ((TrapFrame->Dr6 & 0xf) == 0 && KdbBreakPointToReenable != NULL)
1341 {
1342 /* FIXME: Make sure that the breakpoint was really hit (check bp->Address vs. tf->Eip) */
1343 BreakPoint = KdbBreakPointToReenable;
1344 KdbBreakPointToReenable = NULL;
1345 ASSERT(BreakPoint->Type == KdbBreakPointSoftware ||
1346 BreakPoint->Type == KdbBreakPointTemporary);
1347
1348 /*
1349 * Reenable the breakpoint we disabled to execute the breakpointed
1350 * instruction.
1351 */
1352 if (!NT_SUCCESS(KdbpOverwriteInstruction(KdbCurrentProcess, BreakPoint->Address, 0xCC,
1353 &BreakPoint->Data.SavedInstruction)))
1354 {
1355 DbgPrint("Warning: Couldn't reenable breakpoint %d\n",
1356 BreakPoint - KdbBreakPoints);
1357 }
1358
1359 /* Unset TF if we are no longer single stepping. */
1360 if (KdbNumSingleSteps == 0)
1361 TrapFrame->Eflags &= ~X86_EFLAGS_TF;
1362 goto continue_execution; /* return */
1363 }
1364
1365 /* Check if we expect a single step */
1366 if ((TrapFrame->Dr6 & 0xf) == 0 && KdbNumSingleSteps > 0)
1367 {
1368 /*ASSERT((TrapFrame->Eflags & X86_EFLAGS_TF) != 0);*/
1369 if (--KdbNumSingleSteps > 0)
1370 {
1371 if ((KdbSingleStepOver && KdbpStepOverInstruction(TrapFrame->Eip)) ||
1372 (!KdbSingleStepOver && KdbpStepIntoInstruction(TrapFrame->Eip)))
1373 {
1374 TrapFrame->Eflags &= ~X86_EFLAGS_TF;
1375 }
1376 else
1377 {
1378 TrapFrame->Eflags |= X86_EFLAGS_TF;
1379 }
1380 goto continue_execution; /* return */
1381 }
1382
1383 TrapFrame->Eflags &= ~X86_EFLAGS_TF;
1384 KdbEnteredOnSingleStep = TRUE;
1385 }
1386 else
1387 {
1388 if (!EnterConditionMet)
1389 {
1390 return ContinueType;
1391 }
1392 DbgPrint("Entered debugger on unexpected debug trap!\n");
1393 }
1394 }
1395 else if (ExpNr == 3)
1396 {
1397 if (KdbInitFileBuffer != NULL)
1398 {
1399 KdbpCliInterpretInitFile();
1400 EnterConditionMet = FALSE;
1401 }
1402 if (!EnterConditionMet)
1403 {
1404 return ContinueType;
1405 }
1406
1407 DbgPrint("Entered debugger on embedded INT3 at 0x%04x:0x%08x.\n",
1408 TrapFrame->Cs & 0xffff, TrapFrame->Eip - 1);
1409 }
1410 else
1411 {
1412 CONST PCHAR ExceptionString = (ExpNr < RTL_NUMBER_OF(ExceptionNrToString)) ?
1413 (ExceptionNrToString[ExpNr]) :
1414 ("Unknown/User defined exception");
1415
1416 if (!EnterConditionMet)
1417 {
1418 return ContinueType;
1419 }
1420
1421 DbgPrint("Entered debugger on %s-chance exception number %d (%s)\n",
1422 FirstChance ? "first" : "last", ExpNr, ExceptionString);
1423 if (ExpNr == 14)
1424 {
1425 /* FIXME: Add noexec memory stuff */
1426 ULONG_PTR Cr2;
1427 ULONG Err;
1428 asm volatile("movl %%cr2, %0" : "=r"(Cr2));
1429 Err = TrapFrame->ErrorCode;
1430 DbgPrint("Memory at 0x%p could not be %s: ", Cr2, (Err & (1 << 1)) ? "written" : "read");
1431 if ((Err & (1 << 0)) == 0)
1432 DbgPrint("Page not present.\n");
1433 else
1434 {
1435 if ((Err & (1 << 3)) != 0)
1436 DbgPrint("Reserved bits in page directory set.\n");
1437 else
1438 DbgPrint("Page protection violation.\n");
1439 }
1440 }
1441 }
1442
1443 /* Once we enter the debugger we do not expect any more single steps to happen */
1444 KdbNumSingleSteps = 0;
1445
1446 /* Update the current process pointer */
1447 KdbCurrentProcess = KdbOriginalProcess = PsGetCurrentProcess();
1448 KdbCurrentThread = KdbOriginalThread = PsGetCurrentThread();
1449 KdbCurrentTrapFrame = &KdbTrapFrame;
1450
1451 /* Setup the KDB trap frame */
1452 KdbpTrapFrameToKdbTrapFrame(TrapFrame, &KdbTrapFrame);
1453
1454 /* Enter critical section */
1455 Ke386SaveFlags(OldEflags);
1456 Ke386DisableInterrupts();
1457
1458 /* Exception inside the debugger? Game over. */
1459 if (InterlockedIncrement(&KdbEntryCount) > 1)
1460 {
1461 Ke386RestoreFlags(OldEflags);
1462 return kdHandleException;
1463 }
1464
1465 /* Call the main loop. */
1466 KdbpInternalEnter();
1467
1468 /* Check if we should single step */
1469 if (KdbNumSingleSteps > 0)
1470 {
1471 if ((KdbSingleStepOver && KdbpStepOverInstruction(KdbCurrentTrapFrame->Tf.Eip)) ||
1472 (!KdbSingleStepOver && KdbpStepIntoInstruction(KdbCurrentTrapFrame->Tf.Eip)))
1473 {
1474 ASSERT((KdbCurrentTrapFrame->Tf.Eflags & X86_EFLAGS_TF) == 0);
1475 /*KdbCurrentTrapFrame->Tf.Eflags &= ~X86_EFLAGS_TF;*/
1476 }
1477 else
1478 {
1479 KdbCurrentTrapFrame->Tf.Eflags |= X86_EFLAGS_TF;
1480 }
1481 }
1482
1483 /* Save the current thread's trapframe */
1484 if (KdbCurrentTrapFrame == &KdbThreadTrapFrame)
1485 {
1486 KdbpKdbTrapFrameToTrapFrame(KdbCurrentTrapFrame, KdbCurrentThread->Tcb.TrapFrame);
1487 }
1488
1489 /* Detach from attached process */
1490 if (KdbCurrentProcess != KdbOriginalProcess)
1491 {
1492 KeUnstackDetachProcess(&KdbApcState);
1493 }
1494
1495 /* Update the exception TrapFrame */
1496 KdbpKdbTrapFrameToTrapFrame(&KdbTrapFrame, TrapFrame);
1497
1498 /* Decrement the entry count */
1499 InterlockedDecrement(&KdbEntryCount);
1500
1501 /* Leave critical section */
1502 Ke386RestoreFlags(OldEflags);
1503
1504 continue_execution:
1505 /* Clear debug status */
1506 if (ExpNr == 1 || ExpNr == 3) /* FIXME: Why clear DR6 on INT3? */
1507 {
1508 /* Set the RF flag so we don't trigger the same breakpoint again. */
1509 if (Resume)
1510 {
1511 TrapFrame->Eflags |= X86_EFLAGS_RF;
1512 }
1513
1514 /* Clear dr6 status flags. */
1515 TrapFrame->Dr6 &= ~0x0000e00f;
1516
1517 }
1518
1519 return ContinueType;
1520 }
1521
1522 VOID
1523 KdbDeleteProcessHook(IN PEPROCESS Process)
1524 {
1525 KdbSymFreeProcessSymbols(Process);
1526
1527 /* FIXME: Delete breakpoints for process */
1528 }
1529
1530 VOID
1531 STDCALL
1532 KdbpGetCommandLineSettings(PCHAR p1)
1533 {
1534 PCHAR p2;
1535
1536 while (p1 && (p2 = strchr(p1, '/')))
1537 {
1538 p2++;
1539
1540 if (!_strnicmp(p2, "KDSERIAL", 8))
1541 {
1542 p2 += 8;
1543 KdbDebugState |= KD_DEBUG_KDSERIAL;
1544 KdpDebugMode.Serial = TRUE;
1545 }
1546 else if (!_strnicmp(p2, "KDNOECHO", 8))
1547 {
1548 p2 += 8;
1549 KdbDebugState |= KD_DEBUG_KDNOECHO;
1550 }
1551
1552 p1 = p2;
1553 }
1554 }