3 * Copyright (C) 2001 David Welch <welch@cwcom.net>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 * PROJECT: ReactOS kernel
22 * FILE: ntoskrnl/dbg/kdb.c
23 * PURPOSE: Kernel debugger
24 * PROGRAMMER: David Welch (welch@mcmail.com)
29 /* INCLUDES ******************************************************************/
31 #include <ddk/ntddk.h>
32 #include <internal/ke.h>
33 #include <internal/ps.h>
36 #include <internal/kd.h>
40 #include <internal/debug.h>
42 /* TYPES *********************************************************************/
44 /* GLOBALS *******************************************************************/
47 DbgContCommand(ULONG Argc, PCH Argv[], PKTRAP_FRAME Tf);
49 DbgRegsCommand(ULONG Argc, PCH Argv[], PKTRAP_FRAME Tf);
51 DbgDRegsCommand(ULONG Argc, PCH Argv[], PKTRAP_FRAME Tf);
53 DbgCRegsCommand(ULONG Argc, PCH Argv[], PKTRAP_FRAME Tf);
55 DbgBugCheckCommand(ULONG Argc, PCH Argv[], PKTRAP_FRAME Tf);
57 DbgBackTraceCommand(ULONG Argc, PCH Argv[], PKTRAP_FRAME Tf);
59 DbgProcessListCommand(ULONG Argc, PCH Argv[], PKTRAP_FRAME Tf);
61 DbgProcessHelpCommand(ULONG Argc, PCH Argv[], PKTRAP_FRAME Tf);
63 DbgShowFilesCommand(ULONG Argc, PCH Argv[], PKTRAP_FRAME Tf);
65 DbgEnableFileCommand(ULONG Argc, PCH Argv[], PKTRAP_FRAME Tf);
67 DbgDisableFileCommand(ULONG Argc, PCH Argv[], PKTRAP_FRAME Tf);
74 ULONG (*Fn)(ULONG Argc, PCH Argv[], PKTRAP_FRAME Tf);
75 } DebuggerCommands[] = {
76 {"cont", "cont", "Exit the debugger", DbgContCommand},
77 {"regs", "regs", "Display general purpose registers", DbgRegsCommand},
78 {"dregs", "dregs", "Display debug registers", DbgDRegsCommand},
79 {"cregs", "cregs", "Display control registers", DbgCRegsCommand},
80 {"bugcheck", "bugcheck", "Bugcheck the system", DbgBugCheckCommand},
81 {"bt", "bt [*frame-address]|[thread-id]","Do a backtrace", DbgBackTraceCommand},
82 {"plist", "plist", "Display processes in the system", DbgProcessListCommand},
83 {"sfiles", "sfiles", "Show files that print debug prints", DbgShowFilesCommand},
84 {"efile", "efile <filename>", "Enable debug prints from file", DbgEnableFileCommand},
85 {"dfile", "dfile <filename>", "Disable debug prints from file", DbgDisableFileCommand},
86 {"help", "help", "Display help screen", DbgProcessHelpCommand},
90 /* FUNCTIONS *****************************************************************/
93 * Convert a string to an unsigned long integer.
95 * Ignores `locale' stuff. Assumes that the upper and lower case
96 * alphabets and digits are each contiguous.
99 strtoul(const char *nptr, char **endptr, int base)
101 const char *s = nptr;
104 unsigned long cutoff;
105 int neg = 0, any, cutlim;
108 * See strtol for comments as to the logic used.
112 } while (isspace(c));
120 if ((base == 0 || base == 16) &&
121 c == '0' && (*s == 'x' || *s == 'X'))
128 base = c == '0' ? 8 : 10;
129 cutoff = (unsigned long)ULONG_MAX / (unsigned long)base;
130 cutlim = (unsigned long)ULONG_MAX % (unsigned long)base;
131 for (acc = 0, any = 0;; c = *s++)
136 c -= isupper(c) ? 'A' - 10 : 'a' - 10;
141 if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim))
156 *endptr = any ? (char *)s - 1 : (char *)nptr;
162 strpbrk(const char* s, const char* accept)
165 for (; (*s) != 0; s++)
167 for (i = 0; accept[i] != 0; i++)
169 if (accept[i] == (*s))
179 KdbGetCommand(PCH Buffer)
185 while ((Key = KdbTryGetCharKeyboard()) == -1);
187 if (Key == '\r' || Key == '\n')
202 DbgProcessHelpCommand(ULONG Argc, PCH Argv[], PKTRAP_FRAME Tf)
206 DbgPrint("Kernel debugger commands:\n");
207 for (i = 0; DebuggerCommands[i].Name != NULL; i++)
209 DbgPrint(" %s", DebuggerCommands[i].Syntax);
210 len = strlen(DebuggerCommands[i].Syntax);
213 for (j = 0; j < 35 - len; j++)
218 DbgPrint(" - %s\n", DebuggerCommands[i].Help);
224 DbgProcessListCommand(ULONG Argc, PCH Argv[], PKTRAP_FRAME Tf)
226 extern LIST_ENTRY PsProcessListHead;
227 PLIST_ENTRY current_entry;
231 if (PsProcessListHead.Flink == NULL)
233 DbgPrint("No processes.\n");
237 DbgPrint("Process list: ");
238 current_entry = PsProcessListHead.Flink;
239 while (current_entry != &PsProcessListHead)
241 current = CONTAINING_RECORD(current_entry, EPROCESS, ProcessListEntry);
242 DbgPrint("%d %.8s", current->UniqueProcessId,
243 current->ImageFileName);
249 current_entry = current_entry->Flink;
255 DbgPrintBackTrace(PULONG Frame, ULONG StackBase, ULONG StackLimit)
259 DbgPrint("Frames: ");
260 while (Frame != NULL && (ULONG)Frame >= StackLimit &&
261 (ULONG)Frame < StackBase)
264 DbgPrint("%.8x ", Frame[1]);
266 KdbPrintAddress((PVOID)Frame[1]);
268 Frame = (PULONG)Frame[0];
279 DbgBackTraceCommand(ULONG Argc, PCH Argv[], PKTRAP_FRAME Tf)
281 ULONG StackBase, StackLimit;
282 extern unsigned int init_stack, init_stack_top;
284 /* Without an argument we print the current stack. */
287 if (PsGetCurrentThread() != NULL)
289 StackBase = (ULONG)PsGetCurrentThread()->Tcb.StackBase;
290 StackLimit = PsGetCurrentThread()->Tcb.StackLimit;
294 StackBase = (ULONG)&init_stack_top;
295 StackLimit = (ULONG)&init_stack;
297 DbgPrintBackTrace((PULONG)Tf->Ebp, StackBase, StackLimit);
300 * If there are two arguments and the second begins with a asterik treat it
301 * as the address of a frame to start printing the back trace from.
303 else if (Argc == 2 && Argv[1][0] == '*')
306 Frame = (PULONG)strtoul(&Argv[1][1], NULL, 0);
307 DbgPrintBackTrace(Frame, ULONG_MAX, 0);
310 * Otherwise treat the argument as the id of a thread whose back trace is to
320 DbgPrintCr0(ULONG Cr0)
341 if (!(Cr0 & (1 << 4)))
349 for (i = 6; i < 16; i++)
353 DbgPrint(" BIT%d", i);
368 for (i = 19; i < 29; i++)
372 DbgPrint(" BIT%d", i);
391 DbgCRegsCommand(ULONG Argc, PCH Argv[], PKTRAP_FRAME Tf)
393 ULONG Cr0, Cr1, Cr2, Cr3, Cr4;
397 __asm__ __volatile__ ("movl %%cr0, %0\n\t" : "=d" (Cr0));
398 /* __asm__ __volatile__ ("movl %%cr1, %0\n\t" : "=d" (Cr1)); */
400 __asm__ __volatile__ ("movl %%cr2, %0\n\t" : "=d" (Cr2));
401 __asm__ __volatile__ ("movl %%cr3, %0\n\t" : "=d" (Cr3));
402 __asm__ __volatile__ ("movl %%cr4, %0\n\t" : "=d" (Cr4));
403 __asm__ __volatile__ ("str %0\n\t" : "=d" (Tr));
404 __asm__ __volatile__ ("sldt %0\n\t" : "=d" (Ldtr));
406 DbgPrint("CR1 %.8x CR2 %.8x CR3 %.8x CR4 %.8x TR %.8x LDTR %.8x\n",
407 Cr1, Cr2, Cr3, Cr4, (ULONG)Tf, Ldtr);
412 DbgDRegsCommand(ULONG Argc, PCH Argv[], PKTRAP_FRAME Tf)
414 DbgPrint("DR0 %.8x DR1 %.8x DR2 %.8x DR3 %.8x DR6 %.8x DR7 %.8x\n",
415 Tf->Dr0, Tf->Dr1, Tf->Dr2, Tf->Dr3, Tf->Dr6, Tf->Dr7);
420 DbgContCommand(ULONG Argc, PCH Argv[], PKTRAP_FRAME Tf)
422 /* Not too difficult. */
427 DbgPrintEflags(ULONG Eflags)
430 if (Eflags & (1 << 0))
434 if (!(Eflags & (1 << 1)))
438 if (Eflags & (1 << 2))
442 if (Eflags & (1 << 3))
446 if (Eflags & (1 << 4))
450 if (Eflags & (1 << 5))
454 if (Eflags & (1 << 6))
458 if (Eflags & (1 << 7))
462 if (Eflags & (1 << 8))
466 if (Eflags & (1 << 9))
470 if (Eflags & (1 << 10))
474 if (Eflags & (1 << 11))
478 if ((Eflags & ((1 << 12) | (1 << 13))) == 0)
482 else if ((Eflags & ((1 << 12) | (1 << 13))) == 1)
486 else if ((Eflags & ((1 << 12) | (1 << 13))) == 2)
490 else if ((Eflags & ((1 << 12) | (1 << 13))) == 3)
494 if (Eflags & (1 << 14))
498 if (Eflags & (1 << 15))
502 if (Eflags & (1 << 16))
506 if (Eflags & (1 << 17))
510 if (Eflags & (1 << 18))
514 if (Eflags & (1 << 19))
518 if (Eflags & (1 << 20))
522 if (Eflags & (1 << 21))
526 if (Eflags & (1 << 22))
530 if (Eflags & (1 << 23))
534 if (Eflags & (1 << 24))
538 if (Eflags & (1 << 25))
542 if (Eflags & (1 << 26))
546 if (Eflags & (1 << 27))
550 if (Eflags & (1 << 28))
554 if (Eflags & (1 << 29))
558 if (Eflags & (1 << 30))
562 if (Eflags & (1 << 31))
570 DbgRegsCommand(ULONG Argc, PCH Argv[], PKTRAP_FRAME Tf)
572 DbgPrint("CS:EIP %.4x:%.8x, EAX %.8x EBX %.8x ECX %.8x EDX %.8x\n",
573 Tf->Cs & 0xFFFF, Tf->Eip, Tf->Eax, Tf->Ebx, Tf->Ecx, Tf->Edx);
574 DbgPrint("ESI %.8x EDI %.8x EBP %.8x SS:ESP %.4x:%.8x\n",
575 Tf->Esi, Tf->Edi, Tf->Ebp, Tf->Ss & 0xFFFF, Tf->Esp);
576 DbgPrintEflags(Tf->Eflags);
581 DbgBugCheckCommand(ULONG Argc, PCH Argv[], PKTRAP_FRAME Tf)
588 DbgShowFilesCommand(ULONG Argc, PCH Argv[], PKTRAP_FRAME Tf)
595 DbgEnableFileCommand(ULONG Argc, PCH Argv[], PKTRAP_FRAME Tf)
599 if (strlen(Argv[1]) > 0)
601 DbgEnableFile(Argv[1]);
608 DbgDisableFileCommand(ULONG Argc, PCH Argv[], PKTRAP_FRAME Tf)
612 if (strlen(Argv[1]) > 0)
614 DbgDisableFile(Argv[1]);
621 KdbDoCommand(PCH CommandLine, PKTRAP_FRAME Tf)
626 static PCH Argv[256];
628 static CHAR OrigCommand[256];
630 strcpy(OrigCommand, CommandLine);
634 while ((s1 = strpbrk(s, "\t ")) != NULL)
644 for (i = 0; DebuggerCommands[i].Name != NULL; i++)
646 if (strcmp(DebuggerCommands[i].Name, Argv[0]) == 0)
648 return(DebuggerCommands[i].Fn(Argc, Argv, Tf));
651 DbgPrint("Command '%s' is unknown.", OrigCommand);
656 KdbMainLoop(PKTRAP_FRAME Tf)
661 DbgPrint("\nEntered kernel debugger (type \"help\" for a list of commands)\n");
664 DbgPrint("\nkdb:> ");
666 KdbGetCommand(Command);
668 s = KdbDoCommand(Command, Tf);
673 KdbInternalEnter(PKTRAP_FRAME Tf)
675 __asm__ __volatile__ ("cli\n\t");
676 (VOID)KdbMainLoop(Tf);
677 __asm__ __volatile__("sti\n\t");
681 KdbEnterDebuggerException(PEXCEPTION_RECORD ExceptionRecord,
683 PKTRAP_FRAME TrapFrame)
685 DbgPrint("Entered debugger on exception number %d.\n",
686 TrapFrame->DebugArgMark);
687 KdbInternalEnter(TrapFrame);
688 return(kdHandleException);