b1329704c16e6dfe6b895a118ade795006cb5f04
[reactos.git] / ntoskrnl / dbg / kdb.c
1 /*
2  *  ReactOS kernel
3  *  Copyright (C) 2001 David Welch <welch@cwcom.net>
4  *
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.
9  *
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.
14  *
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.
18  */
19 /* $Id$
20  *
21  * PROJECT:         ReactOS kernel
22  * FILE:            ntoskrnl/dbg/kdb.c
23  * PURPOSE:         Kernel debugger
24  * PROGRAMMER:      David Welch (welch@mcmail.com)
25  * UPDATE HISTORY:
26  *                  Created 01/03/01
27  */
28
29 /* INCLUDES ******************************************************************/
30
31 #include <ddk/ntddk.h>
32 #include <internal/ke.h>
33 #include <internal/ps.h>
34 #include <limits.h>
35 #include <ctype.h>
36 #include <internal/kd.h>
37 #include "kdb.h"
38
39 #define NDEBUG
40 #include <internal/debug.h>
41
42 /* TYPES *********************************************************************/
43
44 /* GLOBALS *******************************************************************/
45
46 ULONG 
47 DbgContCommand(ULONG Argc, PCH Argv[], PKTRAP_FRAME Tf);
48 ULONG 
49 DbgRegsCommand(ULONG Argc, PCH Argv[], PKTRAP_FRAME Tf);
50 ULONG 
51 DbgDRegsCommand(ULONG Argc, PCH Argv[], PKTRAP_FRAME Tf);
52 ULONG 
53 DbgCRegsCommand(ULONG Argc, PCH Argv[], PKTRAP_FRAME Tf);
54 ULONG 
55 DbgBugCheckCommand(ULONG Argc, PCH Argv[], PKTRAP_FRAME Tf);
56 ULONG
57 DbgBackTraceCommand(ULONG Argc, PCH Argv[], PKTRAP_FRAME Tf);
58 ULONG
59 DbgProcessListCommand(ULONG Argc, PCH Argv[], PKTRAP_FRAME Tf);
60 ULONG
61 DbgProcessHelpCommand(ULONG Argc, PCH Argv[], PKTRAP_FRAME Tf);
62 ULONG
63 DbgShowFilesCommand(ULONG Argc, PCH Argv[], PKTRAP_FRAME Tf);
64 ULONG
65 DbgEnableFileCommand(ULONG Argc, PCH Argv[], PKTRAP_FRAME Tf);
66 ULONG
67 DbgDisableFileCommand(ULONG Argc, PCH Argv[], PKTRAP_FRAME Tf);
68
69 struct
70 {
71   PCH Name;
72   PCH Syntax;
73   PCH Help;
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},
87   {NULL, NULL, NULL}
88 };
89
90 /* FUNCTIONS *****************************************************************/
91
92 /*
93  * Convert a string to an unsigned long integer.
94  *
95  * Ignores `locale' stuff.  Assumes that the upper and lower case
96  * alphabets and digits are each contiguous.
97  */
98 unsigned long
99 strtoul(const char *nptr, char **endptr, int base)
100 {
101   const char *s = nptr;
102   unsigned long acc;
103   int c;
104   unsigned long cutoff;
105   int neg = 0, any, cutlim;
106
107   /*
108    * See strtol for comments as to the logic used.
109    */
110   do {
111     c = *s++;
112   } while (isspace(c));
113   if (c == '-')
114   {
115     neg = 1;
116     c = *s++;
117   }
118   else if (c == '+')
119     c = *s++;
120   if ((base == 0 || base == 16) &&
121       c == '0' && (*s == 'x' || *s == 'X'))
122   {
123     c = s[1];
124     s += 2;
125     base = 16;
126   }
127   if (base == 0)
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++)
132   {
133     if (isdigit(c))
134       c -= '0';
135     else if (isalpha(c))
136       c -= isupper(c) ? 'A' - 10 : 'a' - 10;
137     else
138       break;
139     if (c >= base)
140       break;
141     if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim))
142       any = -1;
143     else {
144       any = 1;
145       acc *= base;
146       acc += c;
147     }
148   }
149   if (any < 0)
150   {
151     acc = ULONG_MAX;
152   }
153   else if (neg)
154     acc = -acc;
155   if (endptr != 0)
156     *endptr = any ? (char *)s - 1 : (char *)nptr;
157   return acc;
158 }
159
160
161 char*
162 strpbrk(const char* s, const char* accept)
163 {
164   int i;
165   for (; (*s) != 0; s++)
166     {
167       for (i = 0; accept[i] != 0; i++)
168         {
169           if (accept[i] == (*s))
170             {
171               return((char *)s);
172             }
173         }
174     }
175   return(NULL);
176 }
177
178 VOID
179 KdbGetCommand(PCH Buffer)
180 {
181   CHAR Key;
182
183   for (;;)
184     {
185       while ((Key = KdbTryGetCharKeyboard()) == -1);
186
187       if (Key == '\r' || Key == '\n')
188         {
189           DbgPrint("\n");
190           *Buffer = 0;
191           return;
192         }
193
194       DbgPrint("%c", Key);
195
196       *Buffer = Key;
197       Buffer++;
198     }
199 }
200
201 ULONG
202 DbgProcessHelpCommand(ULONG Argc, PCH Argv[], PKTRAP_FRAME Tf)
203 {
204   ULONG i, j, len;
205
206   DbgPrint("Kernel debugger commands:\n");
207   for (i = 0; DebuggerCommands[i].Name != NULL; i++)
208     {
209       DbgPrint("  %s", DebuggerCommands[i].Syntax);
210       len = strlen(DebuggerCommands[i].Syntax);
211       if (len < 35)
212         {
213           for (j = 0; j < 35 - len; j++)
214           {
215             DbgPrint(" ");
216           }
217         }
218       DbgPrint(" - %s\n", DebuggerCommands[i].Help);
219     }
220   return(1);
221 }
222
223 ULONG
224 DbgProcessListCommand(ULONG Argc, PCH Argv[], PKTRAP_FRAME Tf)
225 {
226   extern LIST_ENTRY PsProcessListHead;
227   PLIST_ENTRY current_entry;
228   PEPROCESS current;
229   ULONG i = 1;
230
231   if (PsProcessListHead.Flink == NULL)
232     {
233       DbgPrint("No processes.\n");
234       return(1);
235     }
236
237   DbgPrint("Process list: ");
238   current_entry = PsProcessListHead.Flink;
239   while (current_entry != &PsProcessListHead)
240     {
241       current = CONTAINING_RECORD(current_entry, EPROCESS, ProcessListEntry);
242       DbgPrint("%d %.8s", current->UniqueProcessId, 
243                current->ImageFileName);
244       i++;
245       if ((i % 4) == 0)
246         {
247           DbgPrint("\n");
248         }
249       current_entry = current_entry->Flink;
250     }
251   return(1);
252 }
253
254 VOID
255 DbgPrintBackTrace(PULONG Frame, ULONG StackBase, ULONG StackLimit)
256 {
257   ULONG i = 1;
258
259   DbgPrint("Frames:  ");
260   while (Frame != NULL && (ULONG)Frame >= StackLimit && 
261          (ULONG)Frame < StackBase)
262     {
263 #if 0
264       DbgPrint("%.8x  ", Frame[1]);
265 #else
266       KdbPrintAddress((PVOID)Frame[1]);
267 #endif
268       Frame = (PULONG)Frame[0];
269       i++;
270     }
271
272   if ((i % 10) != 0)
273     {
274       DbgPrint("\n");
275     }
276 }
277
278 ULONG
279 DbgBackTraceCommand(ULONG Argc, PCH Argv[], PKTRAP_FRAME Tf)
280 {
281   ULONG StackBase, StackLimit;
282   extern unsigned int init_stack, init_stack_top;
283
284   /* Without an argument we print the current stack. */
285   if (Argc == 1)
286     {
287       if (PsGetCurrentThread() != NULL)
288         {
289           StackBase = (ULONG)PsGetCurrentThread()->Tcb.StackBase;
290           StackLimit = PsGetCurrentThread()->Tcb.StackLimit;
291         }
292       else
293         {
294           StackBase = (ULONG)&init_stack_top;
295           StackLimit = (ULONG)&init_stack;
296         }
297       DbgPrintBackTrace((PULONG)Tf->Ebp, StackBase, StackLimit);
298     }
299   /* 
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.
302    */
303   else if (Argc == 2 && Argv[1][0] == '*')
304     {
305       PULONG Frame;
306       Frame = (PULONG)strtoul(&Argv[1][1], NULL, 0);
307       DbgPrintBackTrace(Frame, ULONG_MAX, 0);
308     }
309   /*
310    * Otherwise treat the argument as the id of a thread whose back trace is to
311    * be printed.
312    */
313   else
314     {
315     }
316   return(1);
317 }
318
319 VOID
320 DbgPrintCr0(ULONG Cr0)
321 {
322   ULONG i;
323
324   DbgPrint("CR0:");
325   if (Cr0 & (1 << 0))
326     {
327       DbgPrint(" PE");
328     }
329   if (Cr0 & (1 << 1))
330     {
331       DbgPrint(" MP");
332     }
333   if (Cr0 & (1 << 2))
334     {
335       DbgPrint(" EM");
336     }
337   if (Cr0 & (1 << 3))
338     {
339       DbgPrint(" TS");
340     }
341   if (!(Cr0 & (1 << 4)))
342     {
343       DbgPrint(" !BIT5");
344     }
345   if (Cr0 & (1 << 5))
346     {
347       DbgPrint(" NE");
348     }
349   for (i = 6; i < 16; i++)
350     {
351       if (Cr0 & (1 << i))
352         {
353           DbgPrint(" BIT%d", i);
354         }
355     }
356   if (Cr0 & (1 << 16))
357     {
358       DbgPrint(" WP");
359     }
360   if (Cr0 & (1 << 17))
361     {
362       DbgPrint(" BIT17");
363     }
364   if (Cr0 & (1 << 18))
365     {
366       DbgPrint(" AM");
367     }
368   for (i = 19; i < 29; i++)
369     {
370       if (Cr0 & (1 << i))
371         {
372           DbgPrint(" BIT%d", i);
373         }
374     }
375   if (Cr0 & (1 << 29))
376     {
377       DbgPrint(" NW");
378     }
379   if (Cr0 & (1 << 30))
380     {
381       DbgPrint(" CD");
382     }
383   if (Cr0 & (1 << 31))
384     {
385       DbgPrint(" PG");
386     }
387   DbgPrint("\n");
388 }
389
390 ULONG 
391 DbgCRegsCommand(ULONG Argc, PCH Argv[], PKTRAP_FRAME Tf)
392 {
393   ULONG Cr0, Cr1, Cr2, Cr3, Cr4;
394   ULONG Ldtr;
395   USHORT Tr;
396   
397   __asm__ __volatile__ ("movl %%cr0, %0\n\t" : "=d" (Cr0));
398   /*  __asm__ __volatile__ ("movl %%cr1, %0\n\t" : "=d" (Cr1)); */
399   Cr1 = 0;
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));
405   DbgPrintCr0(Cr0);
406   DbgPrint("CR1 %.8x CR2 %.8x CR3 %.8x CR4 %.8x TR %.8x LDTR %.8x\n",
407            Cr1, Cr2, Cr3, Cr4, (ULONG)Tf, Ldtr);
408   return(1);
409 }
410
411 ULONG 
412 DbgDRegsCommand(ULONG Argc, PCH Argv[], PKTRAP_FRAME Tf)
413 {
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);
416   return(1);
417 }
418
419 ULONG
420 DbgContCommand(ULONG Argc, PCH Argv[], PKTRAP_FRAME Tf)
421 {
422   /* Not too difficult. */
423   return(0);
424 }
425
426 VOID
427 DbgPrintEflags(ULONG Eflags)
428 {
429   DbgPrint("EFLAGS:");
430   if (Eflags & (1 << 0))
431     {
432       DbgPrint(" CF");
433     }
434   if (!(Eflags & (1 << 1)))
435     {
436       DbgPrint(" !BIT1");
437     }
438   if (Eflags & (1 << 2))
439     {
440       DbgPrint(" PF");
441     }
442   if (Eflags & (1 << 3))
443     {
444       DbgPrint(" BIT3");
445     }
446   if (Eflags & (1 << 4))
447     {
448       DbgPrint(" AF");
449     }
450   if (Eflags & (1 << 5))
451     {
452       DbgPrint(" BIT5");
453     }
454   if (Eflags & (1 << 6))
455     {
456       DbgPrint(" ZF");
457     }
458   if (Eflags & (1 << 7))
459     {
460       DbgPrint(" SF");
461     }
462   if (Eflags & (1 << 8))
463     {
464       DbgPrint(" TF");
465     }
466   if (Eflags & (1 << 9))
467     {
468       DbgPrint(" IF");
469     }
470   if (Eflags & (1 << 10))
471     {
472       DbgPrint(" DF");
473     }
474   if (Eflags & (1 << 11))
475     {
476       DbgPrint(" OF");
477     }
478   if ((Eflags & ((1 << 12) | (1 << 13))) == 0)
479     {
480       DbgPrint(" IOPL0");
481     }
482   else if ((Eflags & ((1 << 12) | (1 << 13))) == 1)
483     {
484       DbgPrint(" IOPL1");
485     }
486   else if ((Eflags & ((1 << 12) | (1 << 13))) == 2)
487     {
488       DbgPrint(" IOPL2");
489     }
490   else if ((Eflags & ((1 << 12) | (1 << 13))) == 3)
491     {
492       DbgPrint(" IOPL3");
493     }
494   if (Eflags & (1 << 14))
495     {
496       DbgPrint(" NT");
497     }
498   if (Eflags & (1 << 15))
499     {
500       DbgPrint(" BIT15");
501     }
502   if (Eflags & (1 << 16))
503     {
504       DbgPrint(" RF");
505     }
506   if (Eflags & (1 << 17))
507     {
508       DbgPrint(" VF");
509     }
510   if (Eflags & (1 << 18))
511     {
512       DbgPrint(" AC");
513     }
514   if (Eflags & (1 << 19))
515     {
516       DbgPrint(" VIF");
517     }
518   if (Eflags & (1 << 20))
519     {
520       DbgPrint(" VIP");
521     }
522   if (Eflags & (1 << 21))
523     {
524       DbgPrint(" ID");
525     }
526   if (Eflags & (1 << 22))
527     {
528       DbgPrint(" BIT22");
529     }
530   if (Eflags & (1 << 23))
531     {
532       DbgPrint(" BIT23");
533     }
534   if (Eflags & (1 << 24))
535     {
536       DbgPrint(" BIT24");
537     }
538   if (Eflags & (1 << 25))
539     {
540       DbgPrint(" BIT25");
541     }
542   if (Eflags & (1 << 26))
543     {
544       DbgPrint(" BIT26");
545     }
546   if (Eflags & (1 << 27))
547     {
548       DbgPrint(" BIT27");
549     }
550   if (Eflags & (1 << 28))
551     {
552       DbgPrint(" BIT28");
553     }
554   if (Eflags & (1 << 29))
555     {
556       DbgPrint(" BIT29");
557     }
558   if (Eflags & (1 << 30))
559     {
560       DbgPrint(" BIT30");
561     }
562   if (Eflags & (1 << 31))
563     {
564       DbgPrint(" BIT31");
565     }
566   DbgPrint("\n");
567 }
568
569 ULONG
570 DbgRegsCommand(ULONG Argc, PCH Argv[], PKTRAP_FRAME Tf)
571 {
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);
577   return(1);
578 }
579
580 ULONG
581 DbgBugCheckCommand(ULONG Argc, PCH Argv[], PKTRAP_FRAME Tf)
582 {
583   KEBUGCHECK(1);
584   return(1);
585 }
586
587 ULONG
588 DbgShowFilesCommand(ULONG Argc, PCH Argv[], PKTRAP_FRAME Tf)
589 {
590   DbgShowFiles();
591   return(1);
592 }
593
594 ULONG
595 DbgEnableFileCommand(ULONG Argc, PCH Argv[], PKTRAP_FRAME Tf)
596 {
597   if (Argc == 2)
598     {
599       if (strlen(Argv[1]) > 0)
600         {
601           DbgEnableFile(Argv[1]);
602         }
603     }
604   return(1);
605 }
606
607 ULONG
608 DbgDisableFileCommand(ULONG Argc, PCH Argv[], PKTRAP_FRAME Tf)
609 {
610   if (Argc == 2)
611     {
612       if (strlen(Argv[1]) > 0)
613         {
614           DbgDisableFile(Argv[1]);
615         }
616     }
617   return(1);
618 }
619
620 ULONG
621 KdbDoCommand(PCH CommandLine, PKTRAP_FRAME Tf)
622 {
623   ULONG i;
624   PCH s1;
625   PCH s;
626   static PCH Argv[256];
627   ULONG Argc;
628   static CHAR OrigCommand[256];
629
630   strcpy(OrigCommand, CommandLine);
631
632   Argc = 0;
633   s = CommandLine;
634   while ((s1 = strpbrk(s, "\t ")) != NULL)
635     {
636       Argv[Argc] = s;
637       *s1 = 0;
638       s = s1 + 1;
639       Argc++;
640     }
641   Argv[Argc] = s;
642   Argc++;
643
644   for (i = 0; DebuggerCommands[i].Name != NULL; i++)
645     {
646       if (strcmp(DebuggerCommands[i].Name, Argv[0]) == 0)
647         {
648           return(DebuggerCommands[i].Fn(Argc, Argv, Tf));
649         }
650     }
651   DbgPrint("Command '%s' is unknown.", OrigCommand);
652   return(1);
653 }
654
655 VOID
656 KdbMainLoop(PKTRAP_FRAME Tf)
657 {
658   CHAR Command[256];
659   ULONG s;
660
661   DbgPrint("\nEntered kernel debugger (type \"help\" for a list of commands)\n");
662   do
663     {
664       DbgPrint("\nkdb:> ");
665
666       KdbGetCommand(Command);
667
668       s = KdbDoCommand(Command, Tf);    
669     } while (s != 0);
670 }
671
672 VOID
673 KdbInternalEnter(PKTRAP_FRAME Tf)
674 {
675   __asm__ __volatile__ ("cli\n\t");
676   (VOID)KdbMainLoop(Tf);
677   __asm__ __volatile__("sti\n\t");
678 }
679
680 KD_CONTINUE_TYPE
681 KdbEnterDebuggerException(PEXCEPTION_RECORD ExceptionRecord,
682                           PCONTEXT Context,
683                           PKTRAP_FRAME TrapFrame)
684 {
685   DbgPrint("Entered debugger on exception number %d.\n", 
686            TrapFrame->DebugArgMark);
687   KdbInternalEnter(TrapFrame);
688   return(kdHandleException);
689 }