3 * Copyright (C) 2001-2004 ReactOS Team
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 /* $Id: kdb.c,v 1.31 2004/08/31 23:53:40 navaraf Exp $
21 * PROJECT: ReactOS kernel
22 * FILE: ntoskrnl/dbg/kdb.c
23 * PURPOSE: Kernel debugger
24 * PROGRAMMER: David Welch (welch@mcmail.com)
29 /* INCLUDES ******************************************************************/
35 #include <internal/debug.h>
37 /* TYPES *********************************************************************/
39 /* GLOBALS *******************************************************************/
44 BOOL KbdEchoOn
= TRUE
;
53 } KDB_ACTIVE_BREAKPOINT
;
55 #define KDB_MAXIMUM_BREAKPOINT_COUNT (255)
57 static ULONG KdbBreakPointCount
= 0;
58 static KDB_ACTIVE_BREAKPOINT
59 KdbActiveBreakPoints
[KDB_MAXIMUM_BREAKPOINT_COUNT
];
61 static BOOLEAN KdbIgnoreNextSingleStep
= FALSE
;
63 static ULONG KdbLastSingleStepFrom
= 0xFFFFFFFF;
64 static BOOLEAN KdbEnteredOnSingleStep
= FALSE
;
66 ULONG KdbEntryCount
= 0;
70 PsDumpThreads(BOOLEAN System
);
72 DbgContCommand(ULONG Argc
, PCH Argv
[], PKTRAP_FRAME Tf
);
74 DbgEchoToggle(ULONG Argc
, PCH Argv
[], PKTRAP_FRAME Tf
);
76 DbgRegsCommand(ULONG Argc
, PCH Argv
[], PKTRAP_FRAME Tf
);
78 DbgDRegsCommand(ULONG Argc
, PCH Argv
[], PKTRAP_FRAME Tf
);
80 DbgCRegsCommand(ULONG Argc
, PCH Argv
[], PKTRAP_FRAME Tf
);
82 DbgBugCheckCommand(ULONG Argc
, PCH Argv
[], PKTRAP_FRAME Tf
);
84 DbgBackTraceCommand(ULONG Argc
, PCH Argv
[], PKTRAP_FRAME Tf
);
86 DbgAddrCommand(ULONG Argc
, PCH Argv
[], PKTRAP_FRAME Tf
);
88 DbgXCommand(ULONG Argc
, PCH Argv
[], PKTRAP_FRAME Tf
);
90 DbgScriptCommand(ULONG Argc
, PCH Argv
[], PKTRAP_FRAME Tf
);
92 DbgThreadListCommand(ULONG Argc
, PCH Argv
[], PKTRAP_FRAME Tf
);
94 DbgProcessListCommand(ULONG Argc
, PCH Argv
[], PKTRAP_FRAME Tf
);
96 DbgProcessHelpCommand(ULONG Argc
, PCH Argv
[], PKTRAP_FRAME Tf
);
98 DbgShowFilesCommand(ULONG Argc
, PCH Argv
[], PKTRAP_FRAME Tf
);
100 DbgEnableFileCommand(ULONG Argc
, PCH Argv
[], PKTRAP_FRAME Tf
);
102 DbgDisableFileCommand(ULONG Argc
, PCH Argv
[], PKTRAP_FRAME Tf
);
104 DbgDisassemble(ULONG Argc
, PCH Argv
[], PKTRAP_FRAME Tf
);
106 DbgSetBreakPoint(ULONG Argc
, PCH Argv
[], PKTRAP_FRAME Tf
);
108 DbgDeleteBreakPoint(ULONG Argc
, PCH Argv
[], PKTRAP_FRAME Tf
);
110 DbgSetMemoryBreakPoint(ULONG Argc
, PCH Argv
[], PKTRAP_FRAME Tf
);
112 DbgStep(ULONG Argc
, PCH Argv
[], PKTRAP_FRAME Tf
);
114 DbgStepOver(ULONG Argc
, PCH Argv
[], PKTRAP_FRAME Tf
);
116 DbgFinish(ULONG Argc
, PCH Argv
[], PKTRAP_FRAME Tf
);
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",
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",
151 {"finish", "finish", "Runs until the current function exits", DbgFinish
},
152 {"help", "help", "Display help screen", DbgProcessHelpCommand
},
156 volatile DWORD x_dr0
= 0, x_dr1
= 0, x_dr2
= 0, x_dr3
= 0, x_dr7
= 0;
158 extern LONG
KdbDisassemble(ULONG Address
);
159 extern LONG
KdbGetInstLength(ULONG Address
);
161 /* FUNCTIONS *****************************************************************/
164 * Convert a string to an unsigned long integer.
166 * Ignores `locale' stuff. Assumes that the upper and lower case
167 * alphabets and digits are each contiguous.
170 strtoul(const char *nptr
, char **endptr
, int base
)
172 const char *s
= nptr
;
175 unsigned long cutoff
;
176 int neg
= 0, any
, cutlim
;
179 * See strtol for comments as to the logic used.
183 } while (isspace(c
));
191 if ((base
== 0 || base
== 16) &&
192 c
== '0' && (*s
== 'x' || *s
== 'X'))
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
++)
207 c
-= isupper(c
) ? 'A' - 10 : 'a' - 10;
212 if (any
< 0 || acc
> cutoff
|| (acc
== cutoff
&& c
> cutlim
))
227 *endptr
= any
? (char *)s
- 1 : (char *)nptr
;
233 strpbrk(const char* s
, const char* accept
)
236 for (; (*s
) != 0; s
++)
238 for (i
= 0; accept
[i
] != 0; i
++)
240 if (accept
[i
] == (*s
))
250 KdbGetCommand(PCH Buffer
)
254 static UCHAR LastCommand
[256] = "";
256 static CHAR LastKey
= '\0';
258 KbdEchoOn
= !((KdDebugState
& KD_DEBUG_KDNOECHO
) != 0);
262 if (KdDebugState
& KD_DEBUG_KDSERIAL
)
263 while ((Key
= KdbTryGetCharSerial()) == -1);
265 while ((Key
= KdbTryGetCharKeyboard(&ScanCode
)) == -1);
267 if (Key
== '\n' && LastKey
== '\r')
269 /* Ignore this key... */
271 else if (Key
== '\r' || Key
== '\n')
275 Repeat the last command if the user presses enter. Reduces the
276 risk of RSI when single-stepping.
280 strcpy(Buffer
, LastCommand
);
285 strcpy(LastCommand
, Orig
);
290 else if (Key
== BS
|| Key
== DEL
)
297 DbgPrint("%c %c", BS
, BS
);
302 else if (ScanCode
== 72)
305 while (Buffer
> Orig
)
310 DbgPrint("%c %c", BS
, BS
);
314 for (i
= 0; LastCommand
[i
] != 0; i
++)
317 DbgPrint("%c", LastCommand
[i
]);
318 *Buffer
= LastCommand
[i
];
335 KdbDecodeAddress(PUCHAR Buffer
, PULONG Address
)
337 while (isspace(*Buffer
))
341 if (Buffer
[0] == '<')
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];
351 if (AddressString
== NULL
)
353 DbgPrint("Address %x is malformed.\n", Buffer
);
358 while (isspace(*AddressString
))
363 for (i
= 0; ModuleName
[i
] != 0 && !isspace(ModuleName
[i
]); i
++)
365 ModuleNameW
[i
] = (WCHAR
)ModuleName
[i
];
369 /* Find the module. */
370 current_entry
= ModuleTextListHead
.Flink
;
372 while (current_entry
!= &ModuleTextListHead
&&
373 current_entry
!= NULL
)
376 CONTAINING_RECORD(current_entry
, MODULE_TEXT_SECTION
, ListEntry
);
377 if (wcscmp(ModuleNameW
, current
->Name
) == 0)
381 current_entry
= current_entry
->Flink
;
383 if (current_entry
== NULL
|| current_entry
== &ModuleTextListHead
)
385 DbgPrint("Couldn't find module %s.\n", ModuleName
);
388 *Address
= current
->Base
;
389 *Address
+= strtoul(AddressString
, NULL
, 16);
394 *Address
= strtoul(Buffer
, NULL
, 0);
400 KdbOverwriteInst(ULONG Address
, PUCHAR PreviousInst
, UCHAR NewInst
)
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
)
409 return(STATUS_MEMORY_NOT_ALLOCATED
);
411 if (Protect
& (PAGE_READONLY
|PAGE_EXECUTE
|PAGE_EXECUTE_READ
))
413 MmSetPageProtect(PsGetCurrentProcess(), (PVOID
)PAGE_ROUND_DOWN(Address
),
414 (Protect
& ~(PAGE_READONLY
|PAGE_EXECUTE
|PAGE_EXECUTE_READ
)) | PAGE_READWRITE
);
416 /* Copy the old instruction back to the caller. */
417 if (PreviousInst
!= NULL
)
419 Status
= MmSafeCopyFromUser(PreviousInst
, (PUCHAR
)Address
, 1);
420 if (!NT_SUCCESS(Status
))
422 if (Protect
& (PAGE_READONLY
|PAGE_EXECUTE
|PAGE_EXECUTE_READ
))
424 MmSetPageProtect(PsGetCurrentProcess(), (PVOID
)PAGE_ROUND_DOWN(Address
), Protect
);
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
))
433 MmSetPageProtect(PsGetCurrentProcess(), (PVOID
)PAGE_ROUND_DOWN(Address
), Protect
);
440 KdbRenableBreakPoints(VOID
)
443 for (i
= 0; i
< KDB_MAXIMUM_BREAKPOINT_COUNT
; i
++)
445 if (KdbActiveBreakPoints
[i
].Assigned
&&
446 !KdbActiveBreakPoints
[i
].Enabled
)
448 KdbActiveBreakPoints
[i
].Enabled
= TRUE
;
449 (VOID
)KdbOverwriteInst(KdbActiveBreakPoints
[i
].Address
,
450 &KdbActiveBreakPoints
[i
].SavedInst
,
457 KdbIsBreakPointOurs(PKTRAP_FRAME Tf
)
460 for (i
= 0; i
< KDB_MAXIMUM_BREAKPOINT_COUNT
; i
++)
462 if (KdbActiveBreakPoints
[i
].Assigned
&&
463 KdbActiveBreakPoints
[i
].Address
== (Tf
->Eip
- 1))
472 KdbDeleteBreakPoint(ULONG BreakPointNr
)
474 KdbBreakPointCount
--;
475 KdbActiveBreakPoints
[BreakPointNr
].Assigned
= FALSE
;
479 KdbInsertBreakPoint(ULONG Address
, BOOLEAN Temporary
)
484 if (KdbBreakPointCount
== KDB_MAXIMUM_BREAKPOINT_COUNT
)
486 return(STATUS_UNSUCCESSFUL
);
488 for (i
= 0; i
< KDB_MAXIMUM_BREAKPOINT_COUNT
; i
++)
490 if (!KdbActiveBreakPoints
[i
].Assigned
)
495 Status
= KdbOverwriteInst(Address
, &SavedInst
, 0xCC);
496 if (!NT_SUCCESS(Status
))
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
);
509 DbgSetBreakPoint(ULONG Argc
, PCH Argv
[], PKTRAP_FRAME Tf
)
516 DbgPrint("Need an address to set the breakpoint at.\n");
519 /* Stitch the remaining arguments back into a single string. */
520 for (i
= 2; i
< Argc
; i
++)
524 if (!KdbDecodeAddress(Argv
[1], &Addr
))
528 DbgPrint("Setting breakpoint at 0x%X\n", Addr
);
529 if (!NT_SUCCESS(Status
= KdbInsertBreakPoint(Addr
, FALSE
)))
531 DbgPrint("Failed to set breakpoint (Status %X)\n", Status
);
537 DbgDeleteBreakPoint(ULONG Argc
, PCH Argv
[], PKTRAP_FRAME Tf
)
542 DbgPrint("Need a breakpoint number to delete.\n");
545 BreakPointNr
= strtoul(Argv
[1], NULL
, 10);
546 DbgPrint("Deleting breakpoint %d.\n", BreakPointNr
);
547 KdbDeleteBreakPoint(BreakPointNr
);
552 DbgSetMemoryBreakPoint(ULONG Argc
, PCH Argv
[], PKTRAP_FRAME Tf
)
556 ULONG Length
, Address
;
559 if (Argc
!= 2 && Argc
< 5)
561 DbgPrint("ba <0-3> <r|w|e> <1|2|4> <address>\n");
564 DebugRegNr
= strtoul(Argv
[1], NULL
, 10);
567 DbgPrint("Debug register number should be between 0 and 3.\n");
572 /* Clear the breakpoint. */
573 Tf
->Dr7
&= ~(0x3 << (DebugRegNr
* 2));
574 if ((Tf
->Dr7
& 0xFF) == 0)
577 If no breakpoints are enabled then
578 clear the exact match flags.
580 Tf
->Dr7
&= 0xFFFFFCFF;
584 BreakType
= Argv
[2][0];
585 if (BreakType
!= 'r' && BreakType
!= 'w' && BreakType
!= 'e')
587 DbgPrint("Access type to break on should be either 'r', 'w' or 'e'.\n");
590 Length
= strtoul(Argv
[3], NULL
, 10);
591 if (Length
!= 1 && Length
!= 2 && Length
!= 4)
593 DbgPrint("Length of the breakpoint should be one, two or four.\n");
596 if (Length
!= 1 && BreakType
== 'e')
598 DbgPrint("The length of an execution breakpoint should be one.\n");
601 /* Stitch the remaining arguments back into a single string. */
602 for (i
= 4; i
< Argc
; i
++)
606 if (!KdbDecodeAddress(Argv
[4], &Address
))
610 if ((Address
& (Length
- 1)) != 0)
612 DbgPrint("The breakpoint address should be aligned to a multiple of "
613 "the breakpoint length.\n");
617 /* Set the breakpoint address. */
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;
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. */
634 case 'r': Rw
= 3; break;
635 case 'w': Rw
= 1; break;
636 case 'e': Rw
= 0; break;
638 Tf
->Dr7
|= (Rw
<< (16 + (DebugRegNr
* 4)));
639 /* Set the breakpoint length. */
640 Tf
->Dr7
|= ((Length
- 1) << (18 + (DebugRegNr
* 4)));
646 DbgStep(ULONG Argc
, PCH Argv
[], PKTRAP_FRAME Tf
)
648 /* Set the single step flag and return to the interrupted code. */
649 Tf
->Eflags
|= (1 << 8);
650 KdbIgnoreNextSingleStep
= FALSE
;
651 KdbLastSingleStepFrom
= Tf
->Eip
;
656 DbgStepOver(ULONG Argc
, PCH Argv
[], PKTRAP_FRAME Tf
)
658 PUCHAR Eip
= (PUCHAR
)Tf
->Eip
;
659 /* Check if the current instruction is a call. */
660 while (Eip
[0] == 0x66 || Eip
[0] == 0x67)
664 if (Eip
[0] == 0xE8 || Eip
[0] == 0x9A || Eip
[0] == 0xF2 || Eip
[0] == 0xF3 ||
665 (Eip
[0] == 0xFF && (Eip
[1] & 0x38) == 0x10))
667 ULONG NextInst
= Tf
->Eip
+ KdbGetInstLength(Tf
->Eip
);
668 KdbLastSingleStepFrom
= Tf
->Eip
;
669 KdbInsertBreakPoint(NextInst
, TRUE
);
674 return(DbgStep(Argc
, Argv
, Tf
));
679 DbgFinish(ULONG Argc
, PCH Argv
[], PKTRAP_FRAME Tf
)
681 PULONG Ebp
= (PULONG
)Tf
->Ebp
;
684 PKTHREAD CurrentThread
;
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
))
692 DbgPrint("This function doesn't appear to have a valid stack frame.\n");
696 /* Get the address of the caller. */
697 Status
= MmSafeCopyFromUser(&ReturnAddress
, Ebp
+ 1, sizeof(ULONG
));
698 if (!NT_SUCCESS(Status
))
700 DbgPrint("Memory access error (%X) while getting return address.\n",
705 /* Set a temporary breakpoint at that location. */
706 Status
= KdbInsertBreakPoint(ReturnAddress
, TRUE
);
707 if (!NT_SUCCESS(Status
))
709 DbgPrint("Couldn't set a temporary breakpoint at %X (Status %X)\n",
710 ReturnAddress
, Status
);
715 Otherwise start running again and with any luck we will break back into
716 the debugger when the current function returns.
722 DbgDisassemble(ULONG Argc
, PCH Argv
[], PKTRAP_FRAME Tf
)
728 /* Stitch the remaining arguments back into a single string. */
729 for (i
= 2; i
< Argc
; i
++)
733 if (!KdbDecodeAddress(Argv
[1], &Address
))
742 for (i
= 0; i
< 10; i
++)
744 if (!KdbSymPrintAddress((PVOID
)Address
))
746 DbgPrint("<%x>", Address
);
749 InstLen
= KdbDisassemble(Address
);
752 DbgPrint("<INVALID>\n");
763 DbgProcessHelpCommand(ULONG Argc
, PCH Argv
[], PKTRAP_FRAME Tf
)
767 DbgPrint("Kernel debugger commands:\n");
768 for (i
= 0; DebuggerCommands
[i
].Name
!= NULL
; i
++)
770 DbgPrint(" %s", DebuggerCommands
[i
].Syntax
);
771 len
= strlen(DebuggerCommands
[i
].Syntax
);
774 for (j
= 0; j
< 35 - len
; j
++)
779 DbgPrint(" - %s\n", DebuggerCommands
[i
].Help
);
785 DbgThreadListCommand(ULONG Argc
, PCH Argv
[], PKTRAP_FRAME Tf
)
788 if (Argc
== 2 && (!strcmp(Argv
[1], "sys") || !strcmp(Argv
[1], "SYS")))
791 PsDumpThreads(System
);
796 DbgProcessListCommand(ULONG Argc
, PCH Argv
[], PKTRAP_FRAME Tf
)
798 extern LIST_ENTRY PsProcessListHead
;
799 PLIST_ENTRY current_entry
;
803 if (PsProcessListHead
.Flink
== NULL
)
805 DbgPrint("No processes.\n");
809 DbgPrint("Process list: ");
810 current_entry
= PsProcessListHead
.Flink
;
811 while (current_entry
!= &PsProcessListHead
)
813 current
= CONTAINING_RECORD(current_entry
, EPROCESS
, ProcessListEntry
);
814 DbgPrint("%d %.8s", current
->UniqueProcessId
,
815 current
->ImageFileName
);
821 current_entry
= current_entry
->Flink
;
827 DbgPrintBackTrace(PULONG Frame
, ULONG StackBase
, ULONG StackLimit
)
831 DbgPrint("Frames: ");
832 while (Frame
!= NULL
&& (ULONG_PTR
)Frame
>= StackLimit
&&
833 (ULONG_PTR
)Frame
< StackBase
)
835 KdbSymPrintAddress((PVOID
)Frame
[1]);
837 Frame
= (PULONG
)Frame
[0];
848 DbgAddrCommand(ULONG Argc
, PCH Argv
[], PKTRAP_FRAME tf
)
854 Addr
= (PVOID
)strtoul(Argv
[1], NULL
, 0);
855 KdbSymPrintAddress(Addr
);
862 DbgXCommand(ULONG Argc
, PCH Argv
[], PKTRAP_FRAME tf
)
869 Addr
= (PDWORD
)strtoul(Argv
[1], NULL
, 0);
871 Items
= (DWORD
)strtoul(Argv
[2], NULL
, 0);
873 if( !Addr
) return(1);
875 for( i
= 0; i
< Items
; i
++ )
878 if( i
) DbgPrint("\n");
879 DbgPrint("%08x:", (int)(&Addr
[i
]));
881 DbgPrint( "%08x ", Addr
[i
] );
887 static int KjsReadRegValue( void *context
,
891 PVOID
*context_list
= context
;
892 PKJS kjs
= (PKJS
)context_list
[0];
893 JSVirtualMachine
*vm
= kjs
->vm
;
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
;
902 if (args
->u
.vinteger
!= 2 ||
903 args
[1].type
!= JS_STRING
|| args
[2].type
!= JS_STRING
) {
904 return JS_PROPERTY_FOUND
;
907 RtlInitUnicodeString(&PathString
,NULL
);
908 RtlInitUnicodeString(&NameString
,NULL
);
910 cp
= js_string_to_c_string (vm
, &args
[1]);
911 RtlCreateUnicodeStringFromAsciiz(&PathString
,cp
);
913 cp
= js_string_to_c_string (vm
, &args
[2]);
914 RtlCreateUnicodeStringFromAsciiz(&NameString
,cp
);
917 RtlInitUnicodeString(&ValueResult
,NULL
);
918 RtlInitUnicodeString(&DefaultString
,L
"");
919 RtlInitAnsiString(&AnsiResult
,NULL
);
921 QueryTable
->EntryContext
= 0;
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
,
934 RtlFreeUnicodeString(&NameString
);
935 RtlFreeUnicodeString(&PathString
);
937 if (NT_SUCCESS(Status
)) {
938 RtlInitAnsiString(&AnsiResult
,NULL
);
939 RtlUnicodeStringToAnsiString(&AnsiResult
,
942 js_vm_make_string (vm
, result
, AnsiResult
.Buffer
,
943 strlen(AnsiResult
.Buffer
));
944 RtlFreeAnsiString(&AnsiResult
);
946 result
->type
= JS_INTEGER
;
947 result
->u
.vinteger
= Status
;
950 return JS_PROPERTY_FOUND
;
953 static int KjsGetRegister( void *context
,
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
;
963 return JS_PROPERTY_FOUND
;
966 static int KjsGetNthModule( void *context
,
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
;
977 if (args
->u
.vinteger
!= 1 || args
[1].type
!= JS_INTEGER
) {
978 return JS_PROPERTY_FOUND
;
981 current_entry
= ModuleTextListHead
.Flink
;
983 while (current_entry
!= &ModuleTextListHead
&&
984 current_entry
!= NULL
&&
985 n
<= args
[1].u
.vinteger
) {
986 current
= CONTAINING_RECORD(current_entry
, MODULE_TEXT_SECTION
,
988 current_entry
= current_entry
->Flink
;
992 if (current_entry
&& current
) {
993 ANSI_STRING NameStringNarrow
;
994 UNICODE_STRING NameUnicodeString
;
996 RtlInitUnicodeString( &NameUnicodeString
, current
->Name
);
997 RtlUnicodeStringToAnsiString( &NameStringNarrow
,
1001 js_vm_make_array (vm
, result
, 2);
1003 js_vm_make_string (vm
,
1004 &result
->u
.varray
->data
[0],
1005 NameStringNarrow
.Buffer
,
1006 NameStringNarrow
.Length
);
1008 RtlFreeAnsiString(&NameStringNarrow
);
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
;
1015 result
->type
= JS_UNDEFINED
;
1016 return JS_PROPERTY_FOUND
;
1019 static BOOL
FindJSEndMark( PCHAR Buffer
) {
1022 for( i
= 0; Buffer
[i
] && Buffer
[i
+1]; i
++ ) {
1023 if( Buffer
[i
] == ';' && Buffer
[i
+1] == ';' ) return TRUE
;
1029 DbgScriptCommand(ULONG Argc
, PCH Argv
[], PKTRAP_FRAME tf
)
1033 static void *interp
= 0;
1034 void *script_cmd_context
[2];
1036 if( !interp
) interp
= kjs_create_interp(NULL
);
1037 if( !interp
) return 1;
1039 BufferStart
= Buffer
= ExAllocatePool( NonPagedPool
, 4096 );
1040 if( !Buffer
) return 1;
1042 script_cmd_context
[0] = interp
;
1043 script_cmd_context
[1] = &tf
;
1045 kjs_system_register( interp
, "regs", script_cmd_context
,
1047 kjs_system_register( interp
, "regread", script_cmd_context
,
1049 kjs_system_register( interp
, "getmodule", script_cmd_context
,
1055 "'\\\\Registry\\\\Machine\\\\System\\\\"
1056 "CurrentControlSet\\\\Control\\\\Kdb',"
1059 DbgPrint("\nKernel Debugger Script Interface (JavaScript :-)\n");
1060 DbgPrint("Terminate input with ;; and end scripting with .\n");
1063 if( Buffer
!= BufferStart
)
1067 KdbGetCommand( BufferStart
);
1068 if( BufferStart
[0] == '.' ) {
1069 if( BufferStart
!= Buffer
) {
1070 DbgPrint("Input Aborted.\n");
1071 BufferStart
= Buffer
;
1073 /* Single dot input -> exit */
1077 if( FindJSEndMark( Buffer
) ) {
1078 kjs_eval( interp
, Buffer
);
1079 BufferStart
= Buffer
;
1082 BufferStart
= BufferStart
+ strlen(BufferStart
);
1087 ExFreePool( Buffer
);
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
);
1097 DbgBackTraceCommand(ULONG Argc
, PCH Argv
[], PKTRAP_FRAME Tf
)
1099 ULONG_PTR StackBase
, StackLimit
;
1100 extern unsigned int init_stack
, init_stack_top
;
1102 /* Without an argument we print the current stack. */
1105 if (PsGetCurrentThread() != NULL
)
1107 StackBase
= (ULONG_PTR
)PsGetCurrentThread()->Tcb
.StackBase
;
1108 StackLimit
= PsGetCurrentThread()->Tcb
.StackLimit
;
1112 StackBase
= (ULONG_PTR
)&init_stack_top
;
1113 StackLimit
= (ULONG_PTR
)&init_stack
;
1115 DbgPrintBackTrace((PULONG
)&Tf
->DebugEbp
, StackBase
, StackLimit
);
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.
1121 else if (Argc
== 2 && Argv
[1][0] == '*')
1124 Frame
= (PULONG
)strtoul(&Argv
[1][1], NULL
, 0);
1125 DbgPrintBackTrace(Frame
, ULONG_MAX
, 0);
1128 * Otherwise treat the argument as the id of a thread whose back trace is to
1138 DbgPrintCr0(ULONG Cr0
)
1159 if (!(Cr0
& (1 << 4)))
1167 for (i
= 6; i
< 16; i
++)
1171 DbgPrint(" BIT%d", i
);
1174 if (Cr0
& (1 << 16))
1178 if (Cr0
& (1 << 17))
1182 if (Cr0
& (1 << 18))
1186 for (i
= 19; i
< 29; i
++)
1190 DbgPrint(" BIT%d", i
);
1193 if (Cr0
& (1 << 29))
1197 if (Cr0
& (1 << 30))
1201 if (Cr0
& (1 << 31))
1209 DbgCRegsCommand(ULONG Argc
, PCH Argv
[], PKTRAP_FRAME Tf
)
1211 ULONG Cr0
, Cr1
, Cr2
, Cr3
, Cr4
;
1215 __asm__
__volatile__ ("movl %%cr0, %0\n\t" : "=d" (Cr0
));
1216 /* __asm__ __volatile__ ("movl %%cr1, %0\n\t" : "=d" (Cr1)); */
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
));
1224 DbgPrint("CR1 %.8x CR2 %.8x CR3 %.8x CR4 %.8x TR %.8x LDTR %.8x\n",
1225 Cr1
, Cr2
, Cr3
, Cr4
, (ULONG
)Tf
, Ldtr
);
1230 DbgDRegsCommand(ULONG Argc
, PCH Argv
[], PKTRAP_FRAME Tf
)
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
);
1238 DbgContCommand(ULONG Argc
, PCH Argv
[], PKTRAP_FRAME Tf
)
1240 /* Not too difficult. */
1245 DbgEchoToggle(ULONG Argc
, PCH Argv
[], PKTRAP_FRAME Tf
)
1247 KbdEchoOn
= !KbdEchoOn
;
1252 DbgPrintEflags(ULONG Eflags
)
1254 DbgPrint("EFLAGS:");
1255 if (Eflags
& (1 << 0))
1259 if (!(Eflags
& (1 << 1)))
1263 if (Eflags
& (1 << 2))
1267 if (Eflags
& (1 << 3))
1271 if (Eflags
& (1 << 4))
1275 if (Eflags
& (1 << 5))
1279 if (Eflags
& (1 << 6))
1283 if (Eflags
& (1 << 7))
1287 if (Eflags
& (1 << 8))
1291 if (Eflags
& (1 << 9))
1295 if (Eflags
& (1 << 10))
1299 if (Eflags
& (1 << 11))
1303 if ((Eflags
& ((1 << 12) | (1 << 13))) == 0)
1307 else if ((Eflags
& ((1 << 12) | (1 << 13))) == 1)
1311 else if ((Eflags
& ((1 << 12) | (1 << 13))) == 2)
1315 else if ((Eflags
& ((1 << 12) | (1 << 13))) == 3)
1319 if (Eflags
& (1 << 14))
1323 if (Eflags
& (1 << 15))
1327 if (Eflags
& (1 << 16))
1331 if (Eflags
& (1 << 17))
1335 if (Eflags
& (1 << 18))
1339 if (Eflags
& (1 << 19))
1343 if (Eflags
& (1 << 20))
1347 if (Eflags
& (1 << 21))
1351 if (Eflags
& (1 << 22))
1355 if (Eflags
& (1 << 23))
1359 if (Eflags
& (1 << 24))
1363 if (Eflags
& (1 << 25))
1367 if (Eflags
& (1 << 26))
1371 if (Eflags
& (1 << 27))
1375 if (Eflags
& (1 << 28))
1379 if (Eflags
& (1 << 29))
1383 if (Eflags
& (1 << 30))
1387 if (Eflags
& (1 << 31))
1395 DbgRegsCommand(ULONG Argc
, PCH Argv
[], PKTRAP_FRAME Tf
)
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
);
1406 DbgBugCheckCommand(ULONG Argc
, PCH Argv
[], PKTRAP_FRAME Tf
)
1408 KEBUGCHECK(0xDEADDEAD);
1413 DbgShowFilesCommand(ULONG Argc
, PCH Argv
[], PKTRAP_FRAME Tf
)
1420 DbgEnableFileCommand(ULONG Argc
, PCH Argv
[], PKTRAP_FRAME Tf
)
1424 if (strlen(Argv
[1]) > 0)
1426 DbgEnableFile(Argv
[1]);
1433 DbgDisableFileCommand(ULONG Argc
, PCH Argv
[], PKTRAP_FRAME Tf
)
1437 if (strlen(Argv
[1]) > 0)
1439 DbgDisableFile(Argv
[1]);
1446 KdbCreateThreadHook(PCONTEXT Context
)
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
;
1456 KdbDoCommand(PCH CommandLine
, PKTRAP_FRAME Tf
)
1461 static PCH Argv
[256];
1463 static CHAR OrigCommand
[256];
1465 strcpy(OrigCommand
, CommandLine
);
1469 while ((s1
= strpbrk(s
, "\t ")) != NULL
)
1479 for (i
= 0; DebuggerCommands
[i
].Name
!= NULL
; i
++)
1481 if (strcmp(DebuggerCommands
[i
].Name
, Argv
[0]) == 0)
1483 return(DebuggerCommands
[i
].Fn(Argc
, Argv
, Tf
));
1486 DbgPrint("Command '%s' is unknown.", OrigCommand
);
1491 KdbMainLoop(PKTRAP_FRAME Tf
)
1496 if (!KdbEnteredOnSingleStep
)
1498 DbgPrint("\nEntered kernel debugger (type \"help\" for a list of commands)\n");
1502 if (!KdbSymPrintAddress((PVOID
)Tf
->Eip
))
1504 DbgPrint("<%x>", Tf
->Eip
);
1507 if (KdbDisassemble(Tf
->Eip
) < 0)
1509 DbgPrint("<INVALID>");
1511 KdbEnteredOnSingleStep
= FALSE
;
1512 KdbLastSingleStepFrom
= 0xFFFFFFFF;
1517 DbgPrint("\nkdb:> ");
1519 KdbGetCommand(Command
);
1520 s
= KdbDoCommand(Command
, Tf
);
1525 KdbInternalEnter(PKTRAP_FRAME Tf
)
1527 __asm__
__volatile__ ("cli\n\t");
1529 if (KdDebugState
& KD_DEBUG_SCREEN
)
1531 HalReleaseDisplayOwnership();
1533 (VOID
)KdbMainLoop(Tf
);
1535 __asm__
__volatile__("sti\n\t");
1539 KdbEnterDebuggerException(PEXCEPTION_RECORD ExceptionRecord
,
1541 PKTRAP_FRAME TrapFrame
)
1544 ULONG ExpNr
= (ULONG
)TrapFrame
->DebugArgMark
;
1546 /* Exception inside the debugger? Game over. */
1547 if (KdbEntryCount
> 0)
1549 return(kdHandleException
);
1553 /* Clear the single step flag. */
1554 TrapFrame
->Eflags
&= ~(1 << 8);
1556 Reenable any breakpoints we disabled so we could execute the breakpointed
1559 KdbRenableBreakPoints();
1560 /* Silently ignore a debugger initiated single step. */
1561 if (ExpNr
== 1 && KdbIgnoreNextSingleStep
)
1563 KdbIgnoreNextSingleStep
= FALSE
;
1567 /* If we stopped on one of our breakpoints then let the user know. */
1568 if (ExpNr
== 3 && (BreakPointNr
= KdbIsBreakPointOurs(TrapFrame
)) >= 0)
1570 DbgPrint("Entered debugger on breakpoint %d.\n", BreakPointNr
);
1572 The breakpoint will point to the next instruction by default so
1573 point it back to the start of original instruction.
1577 ..and restore the original instruction.
1579 (VOID
)KdbOverwriteInst(TrapFrame
->Eip
, NULL
,
1580 KdbActiveBreakPoints
[BreakPointNr
].SavedInst
);
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.
1585 if (KdbActiveBreakPoints
[BreakPointNr
].Temporary
)
1587 KdbActiveBreakPoints
[BreakPointNr
].Assigned
= FALSE
;
1588 KdbBreakPointCount
--;
1589 KdbEnteredOnSingleStep
= TRUE
;
1593 KdbActiveBreakPoints
[BreakPointNr
].Enabled
= FALSE
;
1594 TrapFrame
->Eflags
|= (1 << 8);
1595 KdbIgnoreNextSingleStep
= TRUE
;
1598 else if (ExpNr
== 1)
1600 if ((TrapFrame
->Dr6
& 0xF) != 0)
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" : "");
1608 else if (KdbLastSingleStepFrom
!= 0xFFFFFFFF)
1610 KdbEnteredOnSingleStep
= TRUE
;
1614 DbgPrint("Entered debugger on unexpected debug trap.\n");
1619 DbgPrint("Entered debugger on exception number %d.\n", ExpNr
);
1621 KdbInternalEnter(TrapFrame
);
1623 if (ExpNr
!= 1 && ExpNr
!= 3)
1625 return(kdHandleException
);
1629 /* Clear dr6 status flags. */
1630 TrapFrame
->Dr6
&= 0xFFFF1F00;
1631 /* Set the RF flag to we don't trigger the same breakpoint again. */
1634 TrapFrame
->Eflags
|= (1 << 16);