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