fa97e8879e9c22a2c3c47d82f5947cb01b5d6d33
[reactos.git] / reactos / ntoskrnl / dbg / kdb.c
1 /* $Id$
2 *
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/dbg/kdb.c
6 * PURPOSE: Kernel debugger
7 *
8 * PROGRAMMERS: David Welch (welch@mcmail.com)
9 */
10
11 /* INCLUDES ******************************************************************/
12
13 #include <ntoskrnl.h>
14 #include "kdb.h"
15 #include "kjs.h"
16 #define NDEBUG
17 #include <internal/debug.h>
18
19 /* TYPES *********************************************************************/
20
21 /* GLOBALS *******************************************************************/
22
23 #define BS 8
24 #define DEL 127
25
26 BOOL KbdEchoOn = TRUE;
27
28 typedef struct
29 {
30 BOOLEAN Enabled;
31 BOOLEAN Temporary;
32 BOOLEAN Assigned;
33 ULONG Address;
34 UCHAR SavedInst;
35 } KDB_ACTIVE_BREAKPOINT;
36
37 #define KDB_MAXIMUM_BREAKPOINT_COUNT (255)
38
39 static ULONG KdbBreakPointCount = 0;
40 static KDB_ACTIVE_BREAKPOINT
41 KdbActiveBreakPoints[KDB_MAXIMUM_BREAKPOINT_COUNT];
42
43 static BOOLEAN KdbHandleUmode = FALSE;
44 static BOOLEAN KdbHandleHandled = FALSE;
45 static BOOLEAN KdbBreakOnModuleLoad = FALSE;
46
47 static BOOLEAN KdbIgnoreNextSingleStep = FALSE;
48 static ULONG KdbLastSingleStepFrom = 0xFFFFFFFF;
49 static BOOLEAN KdbEnteredOnSingleStep = FALSE;
50
51 ULONG KdbEntryCount = 0;
52
53 int isalpha( int );
54 VOID
55 PsDumpThreads(BOOLEAN System);
56 ULONG
57 DbgContCommand(ULONG Argc, PCH Argv[], PKTRAP_FRAME Tf);
58 ULONG
59 DbgStopCondition(ULONG Aargc, PCH Argv[], PKTRAP_FRAME Tf);
60 ULONG
61 DbgModuleLoadedAction(ULONG Aargc, PCH Argv[], PKTRAP_FRAME Tf);
62 ULONG
63 DbgEchoToggle(ULONG Argc, PCH Argv[], PKTRAP_FRAME Tf);
64 ULONG
65 DbgRegsCommand(ULONG Argc, PCH Argv[], PKTRAP_FRAME Tf);
66 ULONG
67 DbgDRegsCommand(ULONG Argc, PCH Argv[], PKTRAP_FRAME Tf);
68 ULONG
69 DbgCRegsCommand(ULONG Argc, PCH Argv[], PKTRAP_FRAME Tf);
70 ULONG
71 DbgBugCheckCommand(ULONG Argc, PCH Argv[], PKTRAP_FRAME Tf);
72 ULONG
73 DbgBackTraceCommand(ULONG Argc, PCH Argv[], PKTRAP_FRAME Tf);
74 ULONG
75 DbgAddrCommand(ULONG Argc, PCH Argv[], PKTRAP_FRAME Tf);
76 ULONG
77 DbgXCommand(ULONG Argc, PCH Argv[], PKTRAP_FRAME Tf);
78 ULONG
79 DbgScriptCommand(ULONG Argc, PCH Argv[], PKTRAP_FRAME Tf);
80 ULONG
81 DbgThreadListCommand(ULONG Argc, PCH Argv[], PKTRAP_FRAME Tf);
82 ULONG
83 DbgProcessListCommand(ULONG Argc, PCH Argv[], PKTRAP_FRAME Tf);
84 ULONG
85 DbgProcessHelpCommand(ULONG Argc, PCH Argv[], PKTRAP_FRAME Tf);
86 ULONG
87 DbgShowFilesCommand(ULONG Argc, PCH Argv[], PKTRAP_FRAME Tf);
88 ULONG
89 DbgEnableFileCommand(ULONG Argc, PCH Argv[], PKTRAP_FRAME Tf);
90 ULONG
91 DbgDisableFileCommand(ULONG Argc, PCH Argv[], PKTRAP_FRAME Tf);
92 ULONG
93 DbgDisassemble(ULONG Argc, PCH Argv[], PKTRAP_FRAME Tf);
94 ULONG
95 DbgSetBreakPoint(ULONG Argc, PCH Argv[], PKTRAP_FRAME Tf);
96 ULONG
97 DbgDeleteBreakPoint(ULONG Argc, PCH Argv[], PKTRAP_FRAME Tf);
98 ULONG
99 DbgSetMemoryBreakPoint(ULONG Argc, PCH Argv[], PKTRAP_FRAME Tf);
100 ULONG
101 DbgStep(ULONG Argc, PCH Argv[], PKTRAP_FRAME Tf);
102 ULONG
103 DbgStepOver(ULONG Argc, PCH Argv[], PKTRAP_FRAME Tf);
104 ULONG
105 DbgFinish(ULONG Argc, PCH Argv[], PKTRAP_FRAME Tf);
106
107 struct
108 {
109 PCH Name;
110 PCH Syntax;
111 PCH Help;
112 ULONG (*Fn)(ULONG Argc, PCH Argv[], PKTRAP_FRAME Tf);
113 } DebuggerCommands[] = {
114 {"cont", "cont", "Exit the debugger", DbgContCommand},
115 {"echo", "echo", "Toggle serial echo", DbgEchoToggle},
116 {"condition", "condition [all|umode|kmode]", "Kdbg enter condition", DbgStopCondition},
117 {"module-loaded", "module-loaded [break|continue]", "Module-loaded action", DbgModuleLoadedAction},
118
119 {"regs", "regs", "Display general purpose registers", DbgRegsCommand},
120 {"dregs", "dregs", "Display debug registers", DbgDRegsCommand},
121 {"cregs", "cregs", "Display control registers", DbgCRegsCommand},
122 {"bugcheck", "bugcheck", "Bugcheck the system", DbgBugCheckCommand},
123 {"bt", "bt [*frame-address]|[thread-id]","Do a backtrace", DbgBackTraceCommand},
124 {"addr", "addr <address>", "Displays symbol info", DbgAddrCommand},
125 {"x", "x <addr> <words>", "Displays <addr> for <words>", DbgXCommand},
126 {"plist", "plist", "Display processes in the system", DbgProcessListCommand},
127 {"tlist", "tlist [sys]", "Display threads in the system", DbgThreadListCommand},
128 {"sfiles", "sfiles", "Show files that print debug prints", DbgShowFilesCommand},
129 {"efile", "efile <filename>", "Enable debug prints from file", DbgEnableFileCommand},
130 {"dfile", "dfile <filename>", "Disable debug prints from file", DbgDisableFileCommand},
131 {"js", "js", "Script mode", DbgScriptCommand},
132 {"disasm", "disasm <address>", "Disables 10 instructions at <address> or "
133 "eip", DbgDisassemble},
134 {"bp", "bp <address>", "Sets an int3 breakpoint at a given address",
135 DbgSetBreakPoint},
136 {"bc", "bc <breakpoint number>", "Deletes a breakpoint",
137 DbgDeleteBreakPoint},
138 {"ba", "ba <debug register> <access type> <length> <address>",
139 "Sets a breakpoint using a debug register", DbgSetMemoryBreakPoint},
140 {"t", "t", "Steps forward a single instructions", DbgStep},
141 {"p", "p", "Steps forward a single instructions skipping calls",
142 DbgStepOver},
143 {"finish", "finish", "Runs until the current function exits", DbgFinish},
144 {"help", "help", "Display help screen", DbgProcessHelpCommand},
145 {NULL, NULL, NULL}
146 };
147
148 static const char *ExceptionTypeStrings[] =
149 {
150 "Divide Error",
151 "Debug Trap",
152 "NMI",
153 "Breakpoint",
154 "Overflow",
155 "BOUND range exceeded",
156 "Invalid Opcode",
157 "No Math Coprocessor",
158 "Double Fault",
159 "Unknown(9)",
160 "Invalid TSS",
161 "Segment Not Present",
162 "Stack Segment Fault",
163 "General Protection",
164 "Page Fault",
165 "Reserved(15)",
166 "Math Fault",
167 "Alignment Check",
168 "Machine Check",
169 "SIMD Fault"
170 };
171
172 volatile DWORD x_dr0 = 0, x_dr1 = 0, x_dr2 = 0, x_dr3 = 0, x_dr7 = 0;
173
174 extern LONG KdbDisassemble(ULONG Address);
175 extern LONG KdbGetInstLength(ULONG Address);
176
177 /* FUNCTIONS *****************************************************************/
178
179 /*
180 * Convert a string to an unsigned long integer.
181 *
182 * Ignores `locale' stuff. Assumes that the upper and lower case
183 * alphabets and digits are each contiguous.
184 */
185 unsigned long
186 strtoul(const char *nptr, char **endptr, int base)
187 {
188 const char *s = nptr;
189 unsigned long acc;
190 int c;
191 unsigned long cutoff;
192 int neg = 0, any, cutlim;
193
194 /*
195 * See strtol for comments as to the logic used.
196 */
197 do {
198 c = *s++;
199 } while (isspace(c));
200 if (c == '-')
201 {
202 neg = 1;
203 c = *s++;
204 }
205 else if (c == '+')
206 c = *s++;
207 if ((base == 0 || base == 16) &&
208 c == '0' && (*s == 'x' || *s == 'X'))
209 {
210 c = s[1];
211 s += 2;
212 base = 16;
213 }
214 if (base == 0)
215 base = c == '0' ? 8 : 10;
216 cutoff = (unsigned long)ULONG_MAX / (unsigned long)base;
217 cutlim = (unsigned long)ULONG_MAX % (unsigned long)base;
218 for (acc = 0, any = 0;; c = *s++)
219 {
220 if (isdigit(c))
221 c -= '0';
222 else if (isalpha(c))
223 c -= isupper(c) ? 'A' - 10 : 'a' - 10;
224 else
225 break;
226 if (c >= base)
227 break;
228 if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim))
229 any = -1;
230 else {
231 any = 1;
232 acc *= base;
233 acc += c;
234 }
235 }
236 if (any < 0)
237 {
238 acc = ULONG_MAX;
239 }
240 else if (neg)
241 acc = -acc;
242 if (endptr != 0)
243 *endptr = any ? (char *)s - 1 : (char *)nptr;
244 return acc;
245 }
246
247
248 char*
249 strpbrk(const char* s, const char* accept)
250 {
251 int i;
252 for (; (*s) != 0; s++)
253 {
254 for (i = 0; accept[i] != 0; i++)
255 {
256 if (accept[i] == (*s))
257 {
258 return((char *)s);
259 }
260 }
261 }
262 return(NULL);
263 }
264
265
266 #if 0
267 NTSTATUS
268 KdbpSafeReadMemory(PVOID dst, PVOID src, INT size)
269 {
270 INT page, page_end;
271
272 /* check source */
273 page_end = (((ULONG_PTR)src + size) / PAGE_SIZE);
274 for (page = ((ULONG_PTR)src / PAGE_SIZE); page <= page_end; page++)
275 {
276 if (!MmIsPagePresent(NULL, (PVOID)(page * PAGE_SIZE)))
277 return STATUS_UNSUCCESSFUL;
278 }
279
280 /* copy memory */
281 RtlCopyMemory(dst, src, size);
282 return STATUS_SUCCESS;
283 }
284
285
286 NTSTATUS
287 KdbpSafeWriteMemory(PVOID dst, PVOID src, INT size)
288 {
289 return KdbpSafeWriteMemory(dst, src, size);
290 INT page, page_end;
291
292 /* check destination */
293 page_end = (((ULONG_PTR)dst + size) / PAGE_SIZE);
294 for (page = ((ULONG_PTR)dst / PAGE_SIZE); page <= page_end; page++)
295 {
296 if (!MmIsPagePresent(NULL, (PVOID)(page * PAGE_SIZE)))
297 return STATUS_UNSUCCESSFUL;
298 }
299
300 /* copy memory */
301 RtlCopyMemory(dst, src, size);
302 return STATUS_SUCCESS;
303 }
304 #endif /* unused */
305
306
307 VOID
308 KdbGetCommand(PCH Buffer)
309 {
310 CHAR Key;
311 PCH Orig = Buffer;
312 static CHAR LastCommand[256] = "";
313 ULONG ScanCode = 0;
314 static CHAR LastKey = '\0';
315
316 KbdEchoOn = !((KdDebugState & KD_DEBUG_KDNOECHO) != 0);
317
318 for (;;)
319 {
320 if (KdDebugState & KD_DEBUG_KDSERIAL)
321 while ((Key = KdbTryGetCharSerial()) == -1);
322 else
323 while ((Key = KdbTryGetCharKeyboard(&ScanCode)) == -1);
324
325 if (Key == '\n' && LastKey == '\r')
326 {
327 /* Ignore this key... */
328 }
329 else if (Key == '\r' || Key == '\n')
330 {
331 DbgPrint("\n");
332 /*
333 Repeat the last command if the user presses enter. Reduces the
334 risk of RSI when single-stepping.
335 */
336 if (Buffer == Orig)
337 {
338 strcpy(Buffer, LastCommand);
339 }
340 else
341 {
342 *Buffer = 0;
343 strcpy(LastCommand, Orig);
344 }
345 LastKey = Key;
346 return;
347 }
348 else if (Key == BS || Key == DEL)
349 {
350 if (Buffer > Orig)
351 {
352 Buffer--;
353 *Buffer = 0;
354 if (KbdEchoOn)
355 DbgPrint("%c %c", BS, BS);
356 else
357 DbgPrint(" %c", BS);
358 }
359 }
360 else if (ScanCode == 72)
361 {
362 ULONG i;
363 while (Buffer > Orig)
364 {
365 Buffer--;
366 *Buffer = 0;
367 if (KbdEchoOn)
368 DbgPrint("%c %c", BS, BS);
369 else
370 DbgPrint(" %c", BS);
371 }
372 for (i = 0; LastCommand[i] != 0; i++)
373 {
374 if (KbdEchoOn)
375 DbgPrint("%c", LastCommand[i]);
376 *Buffer = LastCommand[i];
377 Buffer++;
378 }
379 }
380 else
381 {
382 if (KbdEchoOn)
383 DbgPrint("%c", Key);
384
385 *Buffer = Key;
386 Buffer++;
387 }
388 LastKey = Key;
389 }
390 }
391
392 BOOLEAN STATIC
393 KdbDecodeAddress(PCHAR Buffer, PULONG Address)
394 {
395 while (isspace(*Buffer))
396 {
397 Buffer++;
398 }
399 if (Buffer[0] == '<')
400 {
401 PCHAR ModuleName = Buffer + 1;
402 PCHAR AddressString = strpbrk(Buffer, ":");
403 extern LIST_ENTRY ModuleTextListHead;
404 PLIST_ENTRY current_entry;
405 MODULE_TEXT_SECTION* current = NULL;
406 static WCHAR ModuleNameW[256];
407 ULONG i;
408
409 if (AddressString == NULL)
410 {
411 DbgPrint("Address %x is malformed.\n", Buffer);
412 return(FALSE);
413 }
414 *AddressString = 0;
415 AddressString++;
416 while (isspace(*AddressString))
417 {
418 AddressString++;
419 }
420
421 for (i = 0; ModuleName[i] != 0 && !isspace(ModuleName[i]); i++)
422 {
423 ModuleNameW[i] = (WCHAR)ModuleName[i];
424 }
425 ModuleNameW[i] = 0;
426
427 /* Find the module. */
428 current_entry = ModuleTextListHead.Flink;
429
430 while (current_entry != &ModuleTextListHead &&
431 current_entry != NULL)
432 {
433 current =
434 CONTAINING_RECORD(current_entry, MODULE_TEXT_SECTION, ListEntry);
435 if (wcscmp(ModuleNameW, current->Name) == 0)
436 {
437 break;
438 }
439 current_entry = current_entry->Flink;
440 }
441 if (current_entry == NULL || current_entry == &ModuleTextListHead)
442 {
443 DbgPrint("Couldn't find module %s.\n", ModuleName);
444 return(FALSE);
445 }
446 *Address = current->Base;
447 *Address += strtoul(AddressString, NULL, 16);
448 return(TRUE);
449 }
450 else
451 {
452 *Address = strtoul(Buffer, NULL, 0);
453 return(TRUE);
454 }
455 }
456
457 NTSTATUS STATIC
458 KdbOverwriteInst(ULONG Address, PUCHAR PreviousInst, UCHAR NewInst)
459 {
460 NTSTATUS Status;
461 ULONG Protect;
462 /* Get the protection for the address. */
463 Protect = MmGetPageProtect(PsGetCurrentProcess(), (PVOID)PAGE_ROUND_DOWN(Address));
464 /* Return if that page isn't present. */
465 if (Protect & PAGE_NOACCESS)
466 {
467 return(STATUS_MEMORY_NOT_ALLOCATED);
468 }
469 if (Protect & (PAGE_READONLY|PAGE_EXECUTE|PAGE_EXECUTE_READ))
470 {
471 MmSetPageProtect(PsGetCurrentProcess(), (PVOID)PAGE_ROUND_DOWN(Address),
472 (Protect & ~(PAGE_READONLY|PAGE_EXECUTE|PAGE_EXECUTE_READ)) | PAGE_READWRITE);
473 }
474 /* Copy the old instruction back to the caller. */
475 if (PreviousInst != NULL)
476 {
477 Status = KdbpSafeReadMemory(PreviousInst, (PUCHAR)Address, 1);
478 if (!NT_SUCCESS(Status))
479 {
480 if (Protect & (PAGE_READONLY|PAGE_EXECUTE|PAGE_EXECUTE_READ))
481 {
482 MmSetPageProtect(PsGetCurrentProcess(), (PVOID)PAGE_ROUND_DOWN(Address), Protect);
483 }
484 return(Status);
485 }
486 }
487 /* Copy the new instruction in its place. */
488 Status = KdbpSafeWriteMemory((PUCHAR)Address, &NewInst, 1);
489 if (Protect & (PAGE_READONLY|PAGE_EXECUTE|PAGE_EXECUTE_READ))
490 {
491 MmSetPageProtect(PsGetCurrentProcess(), (PVOID)PAGE_ROUND_DOWN(Address), Protect);
492 }
493 return Status;
494 }
495
496
497 VOID STATIC
498 KdbRenableBreakPoints(VOID)
499 {
500 ULONG i;
501 for (i = 0; i < KDB_MAXIMUM_BREAKPOINT_COUNT; i++)
502 {
503 if (KdbActiveBreakPoints[i].Assigned &&
504 !KdbActiveBreakPoints[i].Enabled)
505 {
506 KdbActiveBreakPoints[i].Enabled = TRUE;
507 (VOID)KdbOverwriteInst(KdbActiveBreakPoints[i].Address,
508 &KdbActiveBreakPoints[i].SavedInst,
509 0xCC);
510 }
511 }
512 }
513
514 LONG STATIC
515 KdbIsBreakPointOurs(PKTRAP_FRAME Tf)
516 {
517 ULONG i;
518 for (i = 0; i < KDB_MAXIMUM_BREAKPOINT_COUNT; i++)
519 {
520 if (KdbActiveBreakPoints[i].Assigned &&
521 KdbActiveBreakPoints[i].Address == (Tf->Eip - 1))
522 {
523 return(i);
524 }
525 }
526 return(-1);
527 }
528
529 VOID STATIC
530 KdbDeleteBreakPoint(ULONG BreakPointNr)
531 {
532 KdbBreakPointCount--;
533 KdbActiveBreakPoints[BreakPointNr].Assigned = FALSE;
534 }
535
536 NTSTATUS STATIC
537 KdbInsertBreakPoint(ULONG Address, BOOLEAN Temporary)
538 {
539 NTSTATUS Status;
540 UCHAR SavedInst;
541 ULONG i;
542 if (KdbBreakPointCount == KDB_MAXIMUM_BREAKPOINT_COUNT)
543 {
544 return(STATUS_UNSUCCESSFUL);
545 }
546 for (i = 0; i < KDB_MAXIMUM_BREAKPOINT_COUNT; i++)
547 {
548 if (!KdbActiveBreakPoints[i].Assigned)
549 {
550 break;
551 }
552 }
553 Status = KdbOverwriteInst(Address, &SavedInst, 0xCC);
554 if (!NT_SUCCESS(Status))
555 {
556 return(Status);
557 }
558 KdbActiveBreakPoints[i].Assigned = TRUE;
559 KdbActiveBreakPoints[i].Enabled = TRUE;
560 KdbActiveBreakPoints[i].Address = Address;
561 KdbActiveBreakPoints[i].Temporary = Temporary;
562 KdbActiveBreakPoints[i].SavedInst = SavedInst;
563 return(STATUS_SUCCESS);
564 }
565
566 ULONG
567 DbgSetBreakPoint(ULONG Argc, PCH Argv[], PKTRAP_FRAME Tf)
568 {
569 ULONG Addr;
570 NTSTATUS Status;
571 ULONG i;
572 if (Argc < 2)
573 {
574 DbgPrint("Need an address to set the breakpoint at.\n");
575 return(1);
576 }
577 /* Stitch the remaining arguments back into a single string. */
578 for (i = 2; i < Argc; i++)
579 {
580 Argv[i][-1] = ' ';
581 }
582 if (!KdbDecodeAddress(Argv[1], &Addr))
583 {
584 return(1);
585 }
586 DbgPrint("Setting breakpoint at 0x%X\n", Addr);
587 if (!NT_SUCCESS(Status = KdbInsertBreakPoint(Addr, FALSE)))
588 {
589 DbgPrint("Failed to set breakpoint (Status %X)\n", Status);
590 }
591 return(1);
592 }
593
594 ULONG
595 DbgDeleteBreakPoint(ULONG Argc, PCH Argv[], PKTRAP_FRAME Tf)
596 {
597 ULONG BreakPointNr;
598 if (Argc != 2)
599 {
600 DbgPrint("Need a breakpoint number to delete.\n");
601 return(1);
602 }
603 BreakPointNr = strtoul(Argv[1], NULL, 10);
604 DbgPrint("Deleting breakpoint %d.\n", BreakPointNr);
605 KdbDeleteBreakPoint(BreakPointNr);
606 return(1);
607 }
608
609 ULONG
610 DbgSetMemoryBreakPoint(ULONG Argc, PCH Argv[], PKTRAP_FRAME Tf)
611 {
612 ULONG DebugRegNr;
613 UCHAR BreakType;
614 ULONG Length, Address;
615 ULONG Rw = 0;
616 ULONG i;
617 if (Argc != 2 && Argc < 5)
618 {
619 DbgPrint("ba <0-3> <r|w|e> <1|2|4> <address>\n");
620 return(1);
621 }
622 DebugRegNr = strtoul(Argv[1], NULL, 10);
623 if (DebugRegNr >= 4)
624 {
625 DbgPrint("Debug register number should be between 0 and 3.\n");
626 return(1);
627 }
628 if (Argc == 2)
629 {
630 /* Clear the breakpoint. */
631 Tf->Dr7 &= ~(0x3 << (DebugRegNr * 2));
632 if ((Tf->Dr7 & 0xFF) == 0)
633 {
634 /*
635 If no breakpoints are enabled then
636 clear the exact match flags.
637 */
638 Tf->Dr7 &= 0xFFFFFCFF;
639 }
640 return(1);
641 }
642 BreakType = Argv[2][0];
643 if (BreakType != 'r' && BreakType != 'w' && BreakType != 'e')
644 {
645 DbgPrint("Access type to break on should be either 'r', 'w' or 'e'.\n");
646 return(1);
647 }
648 Length = strtoul(Argv[3], NULL, 10);
649 if (Length != 1 && Length != 2 && Length != 4)
650 {
651 DbgPrint("Length of the breakpoint should be one, two or four.\n");
652 return(1);
653 }
654 if (Length != 1 && BreakType == 'e')
655 {
656 DbgPrint("The length of an execution breakpoint should be one.\n");
657 return(1);
658 }
659 /* Stitch the remaining arguments back into a single string. */
660 for (i = 4; i < Argc; i++)
661 {
662 Argv[i][-1] = ' ';
663 }
664 if (!KdbDecodeAddress(Argv[4], &Address))
665 {
666 return(1);
667 }
668 if ((Address & (Length - 1)) != 0)
669 {
670 DbgPrint("The breakpoint address should be aligned to a multiple of "
671 "the breakpoint length.\n");
672 return(1);
673 }
674
675 /* Set the breakpoint address. */
676 switch (DebugRegNr)
677 {
678 case 0: Tf->Dr0 = Address; break;
679 case 1: Tf->Dr1 = Address; break;
680 case 2: Tf->Dr2 = Address; break;
681 case 3: Tf->Dr3 = Address; break;
682 }
683 /* Enable the breakpoint. */
684 Tf->Dr7 |= (0x3 << (DebugRegNr * 2));
685 /* Enable the exact match bits. */
686 Tf->Dr7 |= 0x00000300;
687 /* Clear existing state. */
688 Tf->Dr7 &= ~(0xF << (16 + (DebugRegNr * 4)));
689 /* Set the breakpoint type. */
690 switch (BreakType)
691 {
692 case 'r': Rw = 3; break;
693 case 'w': Rw = 1; break;
694 case 'e': Rw = 0; break;
695 }
696 Tf->Dr7 |= (Rw << (16 + (DebugRegNr * 4)));
697 /* Set the breakpoint length. */
698 Tf->Dr7 |= ((Length - 1) << (18 + (DebugRegNr * 4)));
699
700 return(1);
701 }
702
703 ULONG
704 DbgStep(ULONG Argc, PCH Argv[], PKTRAP_FRAME Tf)
705 {
706 /* Set the single step flag and return to the interrupted code. */
707 Tf->Eflags |= (1 << 8);
708 KdbIgnoreNextSingleStep = FALSE;
709 KdbLastSingleStepFrom = Tf->Eip;
710 return(0);
711 }
712
713 ULONG
714 DbgStepOver(ULONG Argc, PCH Argv[], PKTRAP_FRAME Tf)
715 {
716 PUCHAR Eip;
717 UCHAR Mem[3];
718
719 if (!NT_SUCCESS(KdbpSafeReadMemory(Mem, (PVOID)Tf->Eip, sizeof (Mem))))
720 {
721 DbgPrint("Couldn't access memory at 0x%x\n", (UINT)Tf->Eip);
722 return(1);
723 }
724 Eip = Mem;
725
726 /* Check if the current instruction is a call. */
727 while (Eip[0] == 0x66 || Eip[0] == 0x67)
728 {
729 Eip++;
730 }
731 if (Eip[0] == 0xE8 || Eip[0] == 0x9A || Eip[0] == 0xF2 || Eip[0] == 0xF3 ||
732 (Eip[0] == 0xFF && (Eip[1] & 0x38) == 0x10))
733 {
734 ULONG NextInst = Tf->Eip + KdbGetInstLength(Tf->Eip);
735 KdbLastSingleStepFrom = Tf->Eip;
736 KdbInsertBreakPoint(NextInst, TRUE);
737 return(0);
738 }
739 else
740 {
741 return(DbgStep(Argc, Argv, Tf));
742 }
743 }
744
745 ULONG
746 DbgFinish(ULONG Argc, PCH Argv[], PKTRAP_FRAME Tf)
747 {
748 PULONG Ebp = (PULONG)Tf->Ebp;
749 ULONG ReturnAddress;
750 NTSTATUS Status;
751 PKTHREAD CurrentThread;
752
753 /* Check that ebp points onto the stack. */
754 CurrentThread = KeGetCurrentThread();
755 if (CurrentThread == NULL ||
756 !(Ebp >= (PULONG)CurrentThread->StackLimit &&
757 Ebp <= (PULONG)CurrentThread->StackBase))
758 {
759 DbgPrint("This function doesn't appear to have a valid stack frame.\n");
760 return(1);
761 }
762
763 /* Get the address of the caller. */
764 Status = KdbpSafeReadMemory(&ReturnAddress, Ebp + 1, sizeof(ULONG));
765 if (!NT_SUCCESS(Status))
766 {
767 DbgPrint("Memory access error (%X) while getting return address.\n",
768 Status);
769 return(1);
770 }
771
772 /* Set a temporary breakpoint at that location. */
773 Status = KdbInsertBreakPoint(ReturnAddress, TRUE);
774 if (!NT_SUCCESS(Status))
775 {
776 DbgPrint("Couldn't set a temporary breakpoint at %X (Status %X)\n",
777 ReturnAddress, Status);
778 return(1);
779 }
780
781 /*
782 Otherwise start running again and with any luck we will break back into
783 the debugger when the current function returns.
784 */
785 return(0);
786 }
787
788 ULONG
789 DbgDisassemble(ULONG Argc, PCH Argv[], PKTRAP_FRAME Tf)
790 {
791 ULONG Address, i;
792 LONG InstLen;
793 if (Argc >= 2)
794 {
795 /* Stitch the remaining arguments back into a single string. */
796 for (i = 2; i < Argc; i++)
797 {
798 Argv[i][-1] = ' ';
799 }
800 if (!KdbDecodeAddress(Argv[1], &Address))
801 {
802 return(1);
803 }
804 }
805 else
806 {
807 Address = Tf->Eip;
808 }
809 for (i = 0; i < 10; i++)
810 {
811 if (!KdbSymPrintAddress((PVOID)Address))
812 {
813 DbgPrint("<%x>", Address);
814 }
815 DbgPrint(": ");
816 InstLen = KdbDisassemble(Address);
817 if (InstLen < 0)
818 {
819 DbgPrint("<INVALID>\n");
820 return(1);
821 }
822 DbgPrint("\n");
823 Address += InstLen;
824 }
825
826 return(1);
827 }
828
829 ULONG
830 DbgProcessHelpCommand(ULONG Argc, PCH Argv[], PKTRAP_FRAME Tf)
831 {
832 ULONG i, j, len;
833
834 DbgPrint("Kernel debugger commands:\n");
835 for (i = 0; DebuggerCommands[i].Name != NULL; i++)
836 {
837 DbgPrint(" %s", DebuggerCommands[i].Syntax);
838 len = strlen(DebuggerCommands[i].Syntax);
839 if (len < 35)
840 {
841 for (j = 0; j < 35 - len; j++)
842 {
843 DbgPrint(" ");
844 }
845 }
846 DbgPrint(" - %s\n", DebuggerCommands[i].Help);
847 }
848 return(1);
849 }
850
851 ULONG
852 DbgThreadListCommand(ULONG Argc, PCH Argv[], PKTRAP_FRAME Tf)
853 {
854 BOOL System = FALSE;
855 if (Argc == 2 && (!strcmp(Argv[1], "sys") || !strcmp(Argv[1], "SYS")))
856 System = TRUE;
857
858 PsDumpThreads(System);
859 return(1);
860 }
861
862 ULONG
863 DbgProcessListCommand(ULONG Argc, PCH Argv[], PKTRAP_FRAME Tf)
864 {
865 extern LIST_ENTRY PsActiveProcessHead;
866 PLIST_ENTRY current_entry;
867 PEPROCESS current;
868 ULONG i = 1;
869
870 if (PsActiveProcessHead.Flink == NULL)
871 {
872 DbgPrint("No processes.\n");
873 return(1);
874 }
875
876 DbgPrint("Process list: ");
877 current_entry = PsActiveProcessHead.Flink;
878 while (current_entry != &PsActiveProcessHead)
879 {
880 current = CONTAINING_RECORD(current_entry, EPROCESS, ProcessListEntry);
881 DbgPrint("%d %.8s", current->UniqueProcessId,
882 current->ImageFileName);
883 i++;
884 if ((i % 4) == 0)
885 {
886 DbgPrint("\n");
887 }
888 current_entry = current_entry->Flink;
889 }
890 return(1);
891 }
892
893 VOID
894 DbgPrintBackTrace(PULONG Frame, ULONG_PTR StackBase, ULONG_PTR StackLimit)
895 {
896 PVOID Address;
897
898 DbgPrint("Frames:\n");
899 while (Frame != NULL)
900 {
901 if (!NT_SUCCESS(KdbpSafeReadMemory(&Address, Frame + 1, sizeof (Address))))
902 {
903 DbgPrint("\nCouldn't access memory at 0x%x!\n", (UINT)(Frame + 1));
904 break;
905 }
906 KdbSymPrintAddress(Address);
907 DbgPrint("\n");
908 if (!NT_SUCCESS(KdbpSafeReadMemory(&Frame, Frame, sizeof (Frame))))
909 {
910 DbgPrint("\nCouldn't access memory at 0x%x!\n", (UINT)Frame);
911 break;
912 }
913 }
914 }
915
916 ULONG
917 DbgAddrCommand(ULONG Argc, PCH Argv[], PKTRAP_FRAME tf)
918 {
919 PVOID Addr;
920
921 if (Argc == 2)
922 {
923 Addr = (PVOID)strtoul(Argv[1], NULL, 0);
924 KdbSymPrintAddress(Addr);
925 }
926
927 return(1);
928 }
929
930 ULONG
931 DbgXCommand(ULONG Argc, PCH Argv[], PKTRAP_FRAME tf)
932 {
933 PDWORD Addr = NULL;
934 DWORD Items = 1;
935 DWORD i = 0;
936 DWORD Item;
937
938 if (Argc >= 2)
939 Addr = (PDWORD)strtoul(Argv[1], NULL, 0);
940 if (Argc >= 3)
941 Items = (DWORD)strtoul(Argv[2], NULL, 0);
942
943 if (Addr == NULL)
944 return(1);
945
946 for (i = 0; i < Items; i++)
947 {
948 if( (i % 4) == 0 )
949 {
950 if (i != 0)
951 DbgPrint("\n");
952 DbgPrint("%08x:", (int)(&Addr[i]));
953 }
954 if (!NT_SUCCESS(KdbpSafeReadMemory(&Item, Addr + i, sizeof (Item))))
955 {
956 DbgPrint("\nCouldn't access memory at 0x%x!\n", (UINT)(Addr + i));
957 break;
958 }
959 DbgPrint("%08x ", Item);
960 }
961
962 return(1);
963 }
964
965 static int KjsReadRegValue( void *context,
966 JSNode *result,
967 JSNode *args ) {
968 PCHAR cp;
969 PVOID *context_list = context;
970 PKJS kjs = (PKJS)context_list[0];
971 JSVirtualMachine *vm = kjs->vm;
972 NTSTATUS Status;
973 RTL_QUERY_REGISTRY_TABLE QueryTable[2] = { { 0 } };
974 UNICODE_STRING NameString;
975 UNICODE_STRING PathString;
976 UNICODE_STRING DefaultString;
977 UNICODE_STRING ValueResult;
978 ANSI_STRING AnsiResult;
979
980 if (args->u.vinteger != 2 ||
981 args[1].type != JS_STRING || args[2].type != JS_STRING) {
982 return JS_PROPERTY_FOUND;
983 }
984
985 RtlInitUnicodeString(&PathString,NULL);
986 RtlInitUnicodeString(&NameString,NULL);
987
988 cp = js_string_to_c_string (vm, &args[1]);
989 RtlCreateUnicodeStringFromAsciiz(&PathString,cp);
990 js_free(cp);
991 cp = js_string_to_c_string (vm, &args[2]);
992 RtlCreateUnicodeStringFromAsciiz(&NameString,cp);
993 js_free(cp);
994
995 RtlInitUnicodeString(&ValueResult,NULL);
996 RtlInitUnicodeString(&DefaultString,L"");
997 RtlInitAnsiString(&AnsiResult,NULL);
998
999 QueryTable->EntryContext = 0;
1000 QueryTable->Flags =
1001 RTL_QUERY_REGISTRY_REQUIRED | RTL_QUERY_REGISTRY_DIRECT;
1002 QueryTable->Name = NameString.Buffer;
1003 QueryTable->DefaultType = REG_SZ;
1004 QueryTable->DefaultData = &DefaultString;
1005 QueryTable->EntryContext = &ValueResult;
1006 Status = RtlQueryRegistryValues( RTL_REGISTRY_ABSOLUTE,
1007 PathString.Buffer,
1008 QueryTable,
1009 NULL,
1010 NULL );
1011
1012 RtlFreeUnicodeString(&NameString);
1013 RtlFreeUnicodeString(&PathString);
1014
1015 if (NT_SUCCESS(Status)) {
1016 RtlInitAnsiString(&AnsiResult,NULL);
1017 RtlUnicodeStringToAnsiString(&AnsiResult,
1018 &ValueResult,
1019 TRUE);
1020 js_vm_make_string (vm, result, AnsiResult.Buffer,
1021 strlen(AnsiResult.Buffer));
1022 RtlFreeAnsiString(&AnsiResult);
1023 } else {
1024 result->type = JS_INTEGER;
1025 result->u.vinteger = Status;
1026 }
1027
1028 return JS_PROPERTY_FOUND;
1029 }
1030
1031 static int KjsGetRegister( void *context,
1032 JSNode *result,
1033 JSNode *args ) {
1034 PVOID *context_list = context;
1035 if( args->u.vinteger == 1 && args->type == JS_INTEGER ) {
1036 DWORD Result = ((DWORD *)context_list[1])[args[1].u.vinteger];
1037 result->type = JS_INTEGER;
1038 result->u.vinteger = Result;
1039 }
1040
1041 return JS_PROPERTY_FOUND;
1042 }
1043
1044 static int KjsGetNthModule( void *context,
1045 JSNode *result,
1046 JSNode *args ) {
1047 PVOID *context_list = context;
1048 PKJS kjs = (PKJS)context_list[0];
1049 JSVirtualMachine *vm = kjs->vm;
1050 PLIST_ENTRY current_entry;
1051 MODULE_TEXT_SECTION *current = NULL;
1052 extern LIST_ENTRY ModuleTextListHead;
1053 int n = 0;
1054
1055 if (args->u.vinteger != 1 || args[1].type != JS_INTEGER) {
1056 return JS_PROPERTY_FOUND;
1057 }
1058
1059 current_entry = ModuleTextListHead.Flink;
1060
1061 while (current_entry != &ModuleTextListHead &&
1062 current_entry != NULL &&
1063 n <= args[1].u.vinteger) {
1064 current = CONTAINING_RECORD(current_entry, MODULE_TEXT_SECTION,
1065 ListEntry);
1066 current_entry = current_entry->Flink;
1067 n++;
1068 }
1069
1070 if (current_entry && current) {
1071 ANSI_STRING NameStringNarrow;
1072 UNICODE_STRING NameUnicodeString;
1073
1074 RtlInitUnicodeString( &NameUnicodeString, current->Name );
1075 RtlUnicodeStringToAnsiString( &NameStringNarrow,
1076 &NameUnicodeString,
1077 TRUE );
1078
1079 js_vm_make_array (vm, result, 2);
1080
1081 js_vm_make_string (vm,
1082 &result->u.varray->data[0],
1083 NameStringNarrow.Buffer,
1084 NameStringNarrow.Length);
1085
1086 RtlFreeAnsiString(&NameStringNarrow);
1087
1088 result->u.varray->data[1].type = JS_INTEGER;
1089 result->u.varray->data[1].u.vinteger = (DWORD)current->Base;
1090 result->type = JS_ARRAY;
1091 return JS_PROPERTY_FOUND;
1092 }
1093 result->type = JS_UNDEFINED;
1094 return JS_PROPERTY_FOUND;
1095 }
1096
1097 static BOOL FindJSEndMark( PCHAR Buffer ) {
1098 int i;
1099
1100 for( i = 0; Buffer[i] && Buffer[i+1]; i++ ) {
1101 if( Buffer[i] == ';' && Buffer[i+1] == ';' ) return TRUE;
1102 }
1103 return FALSE;
1104 }
1105
1106 ULONG
1107 DbgScriptCommand(ULONG Argc, PCH Argv[], PKTRAP_FRAME tf)
1108 {
1109 PCHAR Buffer;
1110 PCHAR BufferStart;
1111 static void *interp = 0;
1112 void *script_cmd_context[2];
1113
1114 if( !interp ) interp = kjs_create_interp(NULL);
1115 if( !interp ) return 1;
1116
1117 BufferStart = Buffer = ExAllocatePool( NonPagedPool, 4096 );
1118 if( !Buffer ) return 1;
1119
1120 script_cmd_context[0] = interp;
1121 script_cmd_context[1] = &tf;
1122
1123 kjs_system_register( interp, "regs", script_cmd_context,
1124 KjsGetRegister );
1125 kjs_system_register( interp, "regread", script_cmd_context,
1126 KjsReadRegValue );
1127 kjs_system_register( interp, "getmodule", script_cmd_context,
1128 KjsGetNthModule );
1129
1130 kjs_eval( interp,
1131 "eval("
1132 "System.regread("
1133 "'\\\\Registry\\\\Machine\\\\System\\\\"
1134 "CurrentControlSet\\\\Control\\\\Kdb',"
1135 "'kjsinit'));" );
1136
1137 DbgPrint("\nKernel Debugger Script Interface (JavaScript :-)\n");
1138 DbgPrint("Terminate input with ;; and end scripting with .\n");
1139 do
1140 {
1141 if( Buffer != BufferStart )
1142 DbgPrint("..... ");
1143 else
1144 DbgPrint("kjs:> ");
1145 KdbGetCommand( BufferStart );
1146 if( BufferStart[0] == '.' ) {
1147 if( BufferStart != Buffer ) {
1148 DbgPrint("Input Aborted.\n");
1149 BufferStart = Buffer;
1150 } else {
1151 /* Single dot input -> exit */
1152 break;
1153 }
1154 } else {
1155 if( FindJSEndMark( Buffer ) ) {
1156 kjs_eval( interp, Buffer );
1157 BufferStart = Buffer;
1158 DbgPrint("\n");
1159 } else {
1160 BufferStart = BufferStart + strlen(BufferStart);
1161 }
1162 }
1163 } while (TRUE);
1164
1165 ExFreePool( Buffer );
1166
1167 kjs_system_unregister( interp, script_cmd_context, KjsGetRegister );
1168 kjs_system_unregister( interp, script_cmd_context, KjsReadRegValue );
1169 kjs_system_unregister( interp, script_cmd_context, KjsGetNthModule );
1170
1171 return(1);
1172 }
1173
1174 ULONG
1175 DbgBackTraceCommand(ULONG Argc, PCH Argv[], PKTRAP_FRAME Tf)
1176 {
1177 ULONG_PTR StackBase, StackLimit;
1178 extern unsigned int init_stack, init_stack_top;
1179
1180 /* Without an argument we print the current stack. */
1181 if (Argc == 1)
1182 {
1183 if (PsGetCurrentThread() != NULL)
1184 {
1185 StackBase = (ULONG_PTR)PsGetCurrentThread()->Tcb.StackBase;
1186 StackLimit = PsGetCurrentThread()->Tcb.StackLimit;
1187 }
1188 else
1189 {
1190 StackBase = (ULONG_PTR)init_stack_top;
1191 StackLimit = (ULONG_PTR)init_stack;
1192 }
1193 DbgPrintBackTrace((PULONG)&Tf->DebugEbp, StackBase, StackLimit);
1194 }
1195 /*
1196 * If there are two arguments and the second begins with a asterik treat it
1197 * as the address of a frame to start printing the back trace from.
1198 */
1199 else if (Argc == 2 && Argv[1][0] == '*')
1200 {
1201 PULONG Frame;
1202 Frame = (PULONG)strtoul(&Argv[1][1], NULL, 0);
1203 DbgPrintBackTrace(Frame, ULONG_MAX, 0);
1204 }
1205 /*
1206 * Otherwise treat the argument as the id of a thread whose back trace is to
1207 * be printed.
1208 */
1209 else
1210 {
1211 }
1212 return(1);
1213 }
1214
1215 VOID
1216 DbgPrintCr0(ULONG Cr0)
1217 {
1218 ULONG i;
1219
1220 DbgPrint("CR0:");
1221 if (Cr0 & (1 << 0))
1222 {
1223 DbgPrint(" PE");
1224 }
1225 if (Cr0 & (1 << 1))
1226 {
1227 DbgPrint(" MP");
1228 }
1229 if (Cr0 & (1 << 2))
1230 {
1231 DbgPrint(" EM");
1232 }
1233 if (Cr0 & (1 << 3))
1234 {
1235 DbgPrint(" TS");
1236 }
1237 if (!(Cr0 & (1 << 4)))
1238 {
1239 DbgPrint(" !BIT5");
1240 }
1241 if (Cr0 & (1 << 5))
1242 {
1243 DbgPrint(" NE");
1244 }
1245 for (i = 6; i < 16; i++)
1246 {
1247 if (Cr0 & (1 << i))
1248 {
1249 DbgPrint(" BIT%d", i);
1250 }
1251 }
1252 if (Cr0 & (1 << 16))
1253 {
1254 DbgPrint(" WP");
1255 }
1256 if (Cr0 & (1 << 17))
1257 {
1258 DbgPrint(" BIT17");
1259 }
1260 if (Cr0 & (1 << 18))
1261 {
1262 DbgPrint(" AM");
1263 }
1264 for (i = 19; i < 29; i++)
1265 {
1266 if (Cr0 & (1 << i))
1267 {
1268 DbgPrint(" BIT%d", i);
1269 }
1270 }
1271 if (Cr0 & (1 << 29))
1272 {
1273 DbgPrint(" NW");
1274 }
1275 if (Cr0 & (1 << 30))
1276 {
1277 DbgPrint(" CD");
1278 }
1279 if (Cr0 & (1 << 31))
1280 {
1281 DbgPrint(" PG");
1282 }
1283 DbgPrint("\n");
1284 }
1285
1286 ULONG
1287 DbgCRegsCommand(ULONG Argc, PCH Argv[], PKTRAP_FRAME Tf)
1288 {
1289 ULONG Cr0, Cr1, Cr2, Cr3, Cr4;
1290 ULONG Ldtr;
1291 USHORT Tr;
1292
1293 __asm__ __volatile__ ("movl %%cr0, %0\n\t" : "=d" (Cr0));
1294 /* __asm__ __volatile__ ("movl %%cr1, %0\n\t" : "=d" (Cr1)); */
1295 Cr1 = 0;
1296 __asm__ __volatile__ ("movl %%cr2, %0\n\t" : "=d" (Cr2));
1297 __asm__ __volatile__ ("movl %%cr3, %0\n\t" : "=d" (Cr3));
1298 __asm__ __volatile__ ("movl %%cr4, %0\n\t" : "=d" (Cr4));
1299 __asm__ __volatile__ ("str %0\n\t" : "=d" (Tr));
1300 __asm__ __volatile__ ("sldt %0\n\t" : "=d" (Ldtr));
1301 DbgPrintCr0(Cr0);
1302 DbgPrint("CR1 %.8x CR2 %.8x CR3 %.8x CR4 %.8x TR %.8x LDTR %.8x\n",
1303 Cr1, Cr2, Cr3, Cr4, (ULONG)Tf, Ldtr);
1304 return(1);
1305 }
1306
1307 ULONG
1308 DbgDRegsCommand(ULONG Argc, PCH Argv[], PKTRAP_FRAME Tf)
1309 {
1310 DbgPrint("Trap : DR0 %.8x DR1 %.8x DR2 %.8x DR3 %.8x DR6 %.8x DR7 %.8x\n",
1311 Tf->Dr0, Tf->Dr1, Tf->Dr2, Tf->Dr3, Tf->Dr6, Tf->Dr7);
1312 return(1);
1313 }
1314
1315 ULONG
1316 DbgContCommand(ULONG Argc, PCH Argv[], PKTRAP_FRAME Tf)
1317 {
1318 /* Not too difficult. */
1319 return(0);
1320 }
1321
1322 ULONG
1323 DbgStopCondition(ULONG Argc, PCH Argv[], PKTRAP_FRAME Tf)
1324 {
1325 if( Argc == 1 ) {
1326 if( KdbHandleHandled ) DbgPrint("all\n");
1327 else if( KdbHandleUmode ) DbgPrint("umode\n");
1328 else DbgPrint("kmode\n");
1329 }
1330 else if( !strcmp(Argv[1],"all") )
1331 { KdbHandleHandled = TRUE; KdbHandleUmode = TRUE; }
1332 else if( !strcmp(Argv[1],"umode") )
1333 { KdbHandleHandled = FALSE; KdbHandleUmode = TRUE; }
1334 else if( !strcmp(Argv[1],"kmode") )
1335 { KdbHandleHandled = FALSE; KdbHandleUmode = FALSE; }
1336
1337 return(TRUE);
1338 }
1339
1340 ULONG
1341 DbgModuleLoadedAction(ULONG Argc, PCH Argv[], PKTRAP_FRAME Tf)
1342 {
1343 if (Argc == 1)
1344 {
1345 if (KdbBreakOnModuleLoad)
1346 DbgPrint("Current setting: break\n");
1347 else
1348 DbgPrint("Current setting: continue\n");
1349 }
1350 else if (!strcmp(Argv[1], "break"))
1351 {
1352 KdbBreakOnModuleLoad = TRUE;
1353 }
1354 else if (!strcmp(Argv[1], "continue"))
1355 {
1356 KdbBreakOnModuleLoad = FALSE;
1357 }
1358 else
1359 {
1360 DbgPrint("Unknown setting: %s\n", Argv[1]);
1361 }
1362
1363 return(TRUE);
1364 }
1365
1366 ULONG
1367 DbgEchoToggle(ULONG Argc, PCH Argv[], PKTRAP_FRAME Tf)
1368 {
1369 KbdEchoOn = !KbdEchoOn;
1370 return(TRUE);
1371 }
1372
1373 VOID
1374 DbgPrintEflags(ULONG Eflags)
1375 {
1376 DbgPrint("EFLAGS:");
1377 if (Eflags & (1 << 0))
1378 {
1379 DbgPrint(" CF");
1380 }
1381 if (!(Eflags & (1 << 1)))
1382 {
1383 DbgPrint(" !BIT1");
1384 }
1385 if (Eflags & (1 << 2))
1386 {
1387 DbgPrint(" PF");
1388 }
1389 if (Eflags & (1 << 3))
1390 {
1391 DbgPrint(" BIT3");
1392 }
1393 if (Eflags & (1 << 4))
1394 {
1395 DbgPrint(" AF");
1396 }
1397 if (Eflags & (1 << 5))
1398 {
1399 DbgPrint(" BIT5");
1400 }
1401 if (Eflags & (1 << 6))
1402 {
1403 DbgPrint(" ZF");
1404 }
1405 if (Eflags & (1 << 7))
1406 {
1407 DbgPrint(" SF");
1408 }
1409 if (Eflags & (1 << 8))
1410 {
1411 DbgPrint(" TF");
1412 }
1413 if (Eflags & (1 << 9))
1414 {
1415 DbgPrint(" IF");
1416 }
1417 if (Eflags & (1 << 10))
1418 {
1419 DbgPrint(" DF");
1420 }
1421 if (Eflags & (1 << 11))
1422 {
1423 DbgPrint(" OF");
1424 }
1425 if ((Eflags & ((1 << 12) | (1 << 13))) == 0)
1426 {
1427 DbgPrint(" IOPL0");
1428 }
1429 else if ((Eflags & ((1 << 12) | (1 << 13))) == 1)
1430 {
1431 DbgPrint(" IOPL1");
1432 }
1433 else if ((Eflags & ((1 << 12) | (1 << 13))) == 2)
1434 {
1435 DbgPrint(" IOPL2");
1436 }
1437 else if ((Eflags & ((1 << 12) | (1 << 13))) == 3)
1438 {
1439 DbgPrint(" IOPL3");
1440 }
1441 if (Eflags & (1 << 14))
1442 {
1443 DbgPrint(" NT");
1444 }
1445 if (Eflags & (1 << 15))
1446 {
1447 DbgPrint(" BIT15");
1448 }
1449 if (Eflags & (1 << 16))
1450 {
1451 DbgPrint(" RF");
1452 }
1453 if (Eflags & (1 << 17))
1454 {
1455 DbgPrint(" VF");
1456 }
1457 if (Eflags & (1 << 18))
1458 {
1459 DbgPrint(" AC");
1460 }
1461 if (Eflags & (1 << 19))
1462 {
1463 DbgPrint(" VIF");
1464 }
1465 if (Eflags & (1 << 20))
1466 {
1467 DbgPrint(" VIP");
1468 }
1469 if (Eflags & (1 << 21))
1470 {
1471 DbgPrint(" ID");
1472 }
1473 if (Eflags & (1 << 22))
1474 {
1475 DbgPrint(" BIT22");
1476 }
1477 if (Eflags & (1 << 23))
1478 {
1479 DbgPrint(" BIT23");
1480 }
1481 if (Eflags & (1 << 24))
1482 {
1483 DbgPrint(" BIT24");
1484 }
1485 if (Eflags & (1 << 25))
1486 {
1487 DbgPrint(" BIT25");
1488 }
1489 if (Eflags & (1 << 26))
1490 {
1491 DbgPrint(" BIT26");
1492 }
1493 if (Eflags & (1 << 27))
1494 {
1495 DbgPrint(" BIT27");
1496 }
1497 if (Eflags & (1 << 28))
1498 {
1499 DbgPrint(" BIT28");
1500 }
1501 if (Eflags & (1 << 29))
1502 {
1503 DbgPrint(" BIT29");
1504 }
1505 if (Eflags & (1 << 30))
1506 {
1507 DbgPrint(" BIT30");
1508 }
1509 if (Eflags & (1 << 31))
1510 {
1511 DbgPrint(" BIT31");
1512 }
1513 DbgPrint("\n");
1514 }
1515
1516 ULONG
1517 DbgRegsCommand(ULONG Argc, PCH Argv[], PKTRAP_FRAME Tf)
1518 {
1519 DbgPrint("CS:EIP %.4x:%.8x, EAX %.8x EBX %.8x ECX %.8x EDX %.8x\n",
1520 Tf->Cs & 0xFFFF, Tf->Eip, Tf->Eax, Tf->Ebx, Tf->Ecx, Tf->Edx);
1521 DbgPrint("ESI %.8x EDI %.8x EBP %.8x SS:ESP %.4x:%.8x\n",
1522 Tf->Esi, Tf->Edi, Tf->Ebp, Tf->Ss & 0xFFFF, Tf->Esp);
1523 DbgPrintEflags(Tf->Eflags);
1524 return(1);
1525 }
1526
1527 ULONG
1528 DbgBugCheckCommand(ULONG Argc, PCH Argv[], PKTRAP_FRAME Tf)
1529 {
1530 KEBUGCHECK(0xDEADDEAD);
1531 return(1);
1532 }
1533
1534 ULONG
1535 DbgShowFilesCommand(ULONG Argc, PCH Argv[], PKTRAP_FRAME Tf)
1536 {
1537 DbgShowFiles();
1538 return(1);
1539 }
1540
1541 ULONG
1542 DbgEnableFileCommand(ULONG Argc, PCH Argv[], PKTRAP_FRAME Tf)
1543 {
1544 if (Argc == 2)
1545 {
1546 if (strlen(Argv[1]) > 0)
1547 {
1548 DbgEnableFile(Argv[1]);
1549 }
1550 }
1551 return(1);
1552 }
1553
1554 ULONG
1555 DbgDisableFileCommand(ULONG Argc, PCH Argv[], PKTRAP_FRAME Tf)
1556 {
1557 if (Argc == 2)
1558 {
1559 if (strlen(Argv[1]) > 0)
1560 {
1561 DbgDisableFile(Argv[1]);
1562 }
1563 }
1564 return(1);
1565 }
1566
1567 VOID
1568 KdbCreateThreadHook(PCONTEXT Context)
1569 {
1570 Context->Dr0 = x_dr0;
1571 Context->Dr1 = x_dr1;
1572 Context->Dr2 = x_dr2;
1573 Context->Dr3 = x_dr3;
1574 Context->Dr7 = x_dr7;
1575 }
1576
1577 ULONG
1578 KdbDoCommand(PCH CommandLine, PKTRAP_FRAME Tf)
1579 {
1580 ULONG i;
1581 PCH s1;
1582 PCH s;
1583 static PCH Argv[256];
1584 ULONG Argc;
1585 static CHAR OrigCommand[256];
1586
1587 strcpy(OrigCommand, CommandLine);
1588
1589 Argc = 0;
1590 s = CommandLine;
1591 while ((s1 = strpbrk(s, "\t ")) != NULL)
1592 {
1593 Argv[Argc] = s;
1594 *s1 = 0;
1595 s = s1 + 1;
1596 Argc++;
1597 }
1598 Argv[Argc] = s;
1599 Argc++;
1600
1601 for (i = 0; DebuggerCommands[i].Name != NULL; i++)
1602 {
1603 if (strcmp(DebuggerCommands[i].Name, Argv[0]) == 0)
1604 {
1605 return(DebuggerCommands[i].Fn(Argc, Argv, Tf));
1606 }
1607 }
1608 DbgPrint("Command '%s' is unknown.", OrigCommand);
1609 return(1);
1610 }
1611
1612 VOID
1613 KdbMainLoop(PKTRAP_FRAME Tf)
1614 {
1615 CHAR Command[256];
1616 ULONG s;
1617
1618 if (!KdbEnteredOnSingleStep)
1619 {
1620 DbgPrint("\nEntered kernel debugger (type \"help\" for a list of commands)\n");
1621 }
1622 else
1623 {
1624 if (!KdbSymPrintAddress((PVOID)Tf->Eip))
1625 {
1626 DbgPrint("<%x>", Tf->Eip);
1627 }
1628 DbgPrint(": ");
1629 if (KdbDisassemble(Tf->Eip) < 0)
1630 {
1631 DbgPrint("<INVALID>");
1632 }
1633 KdbEnteredOnSingleStep = FALSE;
1634 KdbLastSingleStepFrom = 0xFFFFFFFF;
1635 }
1636
1637 do
1638 {
1639 DbgPrint("\nkdb:> ");
1640
1641 KdbGetCommand(Command);
1642 s = KdbDoCommand(Command, Tf);
1643 } while (s != 0);
1644 }
1645
1646 VOID
1647 KdbInternalEnter(PKTRAP_FRAME Tf)
1648 {
1649 __asm__ __volatile__ ("cli\n\t");
1650 KbdDisableMouse();
1651 if (KdDebugState & KD_DEBUG_SCREEN)
1652 {
1653 HalReleaseDisplayOwnership();
1654 }
1655 (VOID)KdbMainLoop(Tf);
1656 KbdEnableMouse();
1657 __asm__ __volatile__("sti\n\t");
1658 }
1659
1660 KD_CONTINUE_TYPE
1661 KdbEnterDebuggerException(PEXCEPTION_RECORD ExceptionRecord,
1662 KPROCESSOR_MODE PreviousMode,
1663 PCONTEXT Context,
1664 PKTRAP_FRAME TrapFrame,
1665 BOOLEAN AlwaysHandle)
1666 {
1667 LONG BreakPointNr;
1668 ULONG ExpNr = (ULONG)TrapFrame->DebugArgMark;
1669
1670 /* Always handle beakpoints */
1671 if (ExpNr != 1 && ExpNr != 3)
1672 {
1673 DbgPrint(":KDBG:Entered:%s:%s\n",
1674 PreviousMode==KernelMode ? "kmode" : "umode",
1675 AlwaysHandle ? "always" : "if-unhandled");
1676
1677 /* If we aren't handling umode exceptions then return */
1678 if (PreviousMode == UserMode && !KdbHandleUmode && !AlwaysHandle)
1679 {
1680 return kdHandleException;
1681 }
1682
1683 /* If the exception would be unhandled (and we care) then handle it */
1684 if (PreviousMode == KernelMode && !KdbHandleHandled && !AlwaysHandle)
1685 {
1686 return kdHandleException;
1687 }
1688 }
1689
1690 /* Exception inside the debugger? Game over. */
1691 if (KdbEntryCount > 0)
1692 {
1693 return(kdHandleException);
1694 }
1695 KdbEntryCount++;
1696
1697 /* Clear the single step flag. */
1698 TrapFrame->Eflags &= ~(1 << 8);
1699 /*
1700 Reenable any breakpoints we disabled so we could execute the breakpointed
1701 instructions.
1702 */
1703 KdbRenableBreakPoints();
1704 /* Silently ignore a debugger initiated single step. */
1705 if (ExpNr == 1 && KdbIgnoreNextSingleStep)
1706 {
1707 KdbIgnoreNextSingleStep = FALSE;
1708 KdbEntryCount--;
1709 return(kdContinue);
1710 }
1711 /* If we stopped on one of our breakpoints then let the user know. */
1712 if (ExpNr == 3 && (BreakPointNr = KdbIsBreakPointOurs(TrapFrame)) >= 0)
1713 {
1714 DbgPrint("Entered debugger on breakpoint %d.\n", BreakPointNr);
1715 /*
1716 The breakpoint will point to the next instruction by default so
1717 point it back to the start of original instruction.
1718 */
1719 TrapFrame->Eip--;
1720 /*
1721 ..and restore the original instruction.
1722 */
1723 (VOID)KdbOverwriteInst(TrapFrame->Eip, NULL,
1724 KdbActiveBreakPoints[BreakPointNr].SavedInst);
1725 /*
1726 If this was a breakpoint set by the debugger then delete it otherwise
1727 flag to enable it again after we step over this instruction.
1728 */
1729 if (KdbActiveBreakPoints[BreakPointNr].Temporary)
1730 {
1731 KdbActiveBreakPoints[BreakPointNr].Assigned = FALSE;
1732 KdbBreakPointCount--;
1733 KdbEnteredOnSingleStep = TRUE;
1734 }
1735 else
1736 {
1737 KdbActiveBreakPoints[BreakPointNr].Enabled = FALSE;
1738 TrapFrame->Eflags |= (1 << 8);
1739 KdbIgnoreNextSingleStep = TRUE;
1740 }
1741 }
1742 else if (ExpNr == 1)
1743 {
1744 if ((TrapFrame->Dr6 & 0xF) != 0)
1745 {
1746 DbgPrint("Entered debugger on memory breakpoint(s) %s%s%s%s.\n",
1747 (TrapFrame->Dr6 & 0x1) ? "1" : "",
1748 (TrapFrame->Dr6 & 0x2) ? "2" : "",
1749 (TrapFrame->Dr6 & 0x4) ? "3" : "",
1750 (TrapFrame->Dr6 & 0x8) ? "4" : "");
1751 }
1752 else if (KdbLastSingleStepFrom != 0xFFFFFFFF)
1753 {
1754 KdbEnteredOnSingleStep = TRUE;
1755 }
1756 else
1757 {
1758 DbgPrint("Entered debugger on unexpected debug trap.\n");
1759 }
1760 }
1761 else
1762 {
1763 const char *ExceptionString =
1764 (ExpNr < (sizeof (ExceptionTypeStrings) / sizeof (ExceptionTypeStrings[0]))) ?
1765 (ExceptionTypeStrings[ExpNr]) :
1766 ("Unknown/User defined exception");
1767 DbgPrint("Entered debugger on exception number %d (%s)\n", ExpNr, ExceptionString);
1768 }
1769 KdbInternalEnter(TrapFrame);
1770 KdbEntryCount--;
1771 if (ExpNr != 1 && ExpNr != 3)
1772 {
1773 return(kdHandleException);
1774 }
1775 else
1776 {
1777 /* Clear dr6 status flags. */
1778 TrapFrame->Dr6 &= 0xFFFF1F00;
1779 /* Set the RF flag to we don't trigger the same breakpoint again. */
1780 if (ExpNr == 1)
1781 {
1782 TrapFrame->Eflags |= (1 << 16);
1783 }
1784 return(kdContinue);
1785 }
1786 }
1787
1788 VOID
1789 KdbModuleLoaded(IN PUNICODE_STRING Name)
1790 {
1791 if (!KdbBreakOnModuleLoad)
1792 return;
1793
1794 DbgPrint("Module %wZ loaded.\n", Name);
1795 DbgBreakPointWithStatus(DBG_STATUS_CONTROL_C);
1796 }
1797