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