3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/dbg/kdb.c
6 * PURPOSE: Kernel debugger
8 * PROGRAMMERS: David Welch (welch@mcmail.com)
11 /* INCLUDES ******************************************************************/
17 #include <internal/debug.h>
19 /* TYPES *********************************************************************/
21 /* GLOBALS *******************************************************************/
26 BOOL KbdEchoOn
= TRUE
;
35 } KDB_ACTIVE_BREAKPOINT
;
37 #define KDB_MAXIMUM_BREAKPOINT_COUNT (255)
39 static ULONG KdbBreakPointCount
= 0;
40 static KDB_ACTIVE_BREAKPOINT
41 KdbActiveBreakPoints
[KDB_MAXIMUM_BREAKPOINT_COUNT
];
43 static BOOLEAN KdbHandleUmode
= FALSE
;
44 static BOOLEAN KdbHandleHandled
= FALSE
;
45 static BOOLEAN KdbBreakOnModuleLoad
= FALSE
;
47 static BOOLEAN KdbIgnoreNextSingleStep
= FALSE
;
48 static ULONG KdbLastSingleStepFrom
= 0xFFFFFFFF;
49 static BOOLEAN KdbEnteredOnSingleStep
= FALSE
;
51 ULONG KdbEntryCount
= 0;
55 PsDumpThreads(BOOLEAN System
);
57 DbgContCommand(ULONG Argc
, PCH Argv
[], PKTRAP_FRAME Tf
);
59 DbgStopCondition(ULONG Aargc
, PCH Argv
[], PKTRAP_FRAME Tf
);
61 DbgModuleLoadedAction(ULONG Aargc
, PCH Argv
[], PKTRAP_FRAME Tf
);
63 DbgEchoToggle(ULONG Argc
, PCH Argv
[], PKTRAP_FRAME Tf
);
65 DbgRegsCommand(ULONG Argc
, PCH Argv
[], PKTRAP_FRAME Tf
);
67 DbgDRegsCommand(ULONG Argc
, PCH Argv
[], PKTRAP_FRAME Tf
);
69 DbgCRegsCommand(ULONG Argc
, PCH Argv
[], PKTRAP_FRAME Tf
);
71 DbgBugCheckCommand(ULONG Argc
, PCH Argv
[], PKTRAP_FRAME Tf
);
73 DbgBackTraceCommand(ULONG Argc
, PCH Argv
[], PKTRAP_FRAME Tf
);
75 DbgAddrCommand(ULONG Argc
, PCH Argv
[], PKTRAP_FRAME Tf
);
77 DbgXCommand(ULONG Argc
, PCH Argv
[], PKTRAP_FRAME Tf
);
79 DbgScriptCommand(ULONG Argc
, PCH Argv
[], PKTRAP_FRAME Tf
);
81 DbgThreadListCommand(ULONG Argc
, PCH Argv
[], PKTRAP_FRAME Tf
);
83 DbgProcessListCommand(ULONG Argc
, PCH Argv
[], PKTRAP_FRAME Tf
);
85 DbgProcessHelpCommand(ULONG Argc
, PCH Argv
[], PKTRAP_FRAME Tf
);
87 DbgShowFilesCommand(ULONG Argc
, PCH Argv
[], PKTRAP_FRAME Tf
);
89 DbgEnableFileCommand(ULONG Argc
, PCH Argv
[], PKTRAP_FRAME Tf
);
91 DbgDisableFileCommand(ULONG Argc
, PCH Argv
[], PKTRAP_FRAME Tf
);
93 DbgDisassemble(ULONG Argc
, PCH Argv
[], PKTRAP_FRAME Tf
);
95 DbgSetBreakPoint(ULONG Argc
, PCH Argv
[], PKTRAP_FRAME Tf
);
97 DbgDeleteBreakPoint(ULONG Argc
, PCH Argv
[], PKTRAP_FRAME Tf
);
99 DbgSetMemoryBreakPoint(ULONG Argc
, PCH Argv
[], PKTRAP_FRAME Tf
);
101 DbgStep(ULONG Argc
, PCH Argv
[], PKTRAP_FRAME Tf
);
103 DbgStepOver(ULONG Argc
, PCH Argv
[], PKTRAP_FRAME Tf
);
105 DbgFinish(ULONG Argc
, PCH Argv
[], PKTRAP_FRAME Tf
);
112 ULONG (*Fn
)(ULONG Argc
, PCH Argv
[], PKTRAP_FRAME Tf
);
113 } DebuggerCommands
[] = {
114 {"cont", "cont", "Exit the debugger", DbgContCommand
},
115 {"echo", "echo", "Toggle serial echo", DbgEchoToggle
},
116 {"condition", "condition [all|umode|kmode]", "Kdbg enter condition", DbgStopCondition
},
117 {"module-loaded", "module-loaded [break|continue]", "Module-loaded action", DbgModuleLoadedAction
},
119 {"regs", "regs", "Display general purpose registers", DbgRegsCommand
},
120 {"dregs", "dregs", "Display debug registers", DbgDRegsCommand
},
121 {"cregs", "cregs", "Display control registers", DbgCRegsCommand
},
122 {"bugcheck", "bugcheck", "Bugcheck the system", DbgBugCheckCommand
},
123 {"bt", "bt [*frame-address]|[thread-id]","Do a backtrace", DbgBackTraceCommand
},
124 {"addr", "addr <address>", "Displays symbol info", DbgAddrCommand
},
125 {"x", "x <addr> <words>", "Displays <addr> for <words>", DbgXCommand
},
126 {"plist", "plist", "Display processes in the system", DbgProcessListCommand
},
127 {"tlist", "tlist [sys]", "Display threads in the system", DbgThreadListCommand
},
128 {"sfiles", "sfiles", "Show files that print debug prints", DbgShowFilesCommand
},
129 {"efile", "efile <filename>", "Enable debug prints from file", DbgEnableFileCommand
},
130 {"dfile", "dfile <filename>", "Disable debug prints from file", DbgDisableFileCommand
},
131 {"js", "js", "Script mode", DbgScriptCommand
},
132 {"disasm", "disasm <address>", "Disables 10 instructions at <address> or "
133 "eip", DbgDisassemble
},
134 {"bp", "bp <address>", "Sets an int3 breakpoint at a given address",
136 {"bc", "bc <breakpoint number>", "Deletes a breakpoint",
137 DbgDeleteBreakPoint
},
138 {"ba", "ba <debug register> <access type> <length> <address>",
139 "Sets a breakpoint using a debug register", DbgSetMemoryBreakPoint
},
140 {"t", "t", "Steps forward a single instructions", DbgStep
},
141 {"p", "p", "Steps forward a single instructions skipping calls",
143 {"finish", "finish", "Runs until the current function exits", DbgFinish
},
144 {"help", "help", "Display help screen", DbgProcessHelpCommand
},
148 static const char *ExceptionTypeStrings
[] =
155 "BOUND range exceeded",
157 "No Math Coprocessor",
161 "Segment Not Present",
162 "Stack Segment Fault",
163 "General Protection",
172 volatile DWORD x_dr0
= 0, x_dr1
= 0, x_dr2
= 0, x_dr3
= 0, x_dr7
= 0;
174 extern LONG
KdbDisassemble(ULONG Address
);
175 extern LONG
KdbGetInstLength(ULONG Address
);
177 /* FUNCTIONS *****************************************************************/
180 * Convert a string to an unsigned long integer.
182 * Ignores `locale' stuff. Assumes that the upper and lower case
183 * alphabets and digits are each contiguous.
186 strtoul(const char *nptr
, char **endptr
, int base
)
188 const char *s
= nptr
;
191 unsigned long cutoff
;
192 int neg
= 0, any
, cutlim
;
195 * See strtol for comments as to the logic used.
199 } while (isspace(c
));
207 if ((base
== 0 || base
== 16) &&
208 c
== '0' && (*s
== 'x' || *s
== 'X'))
215 base
= c
== '0' ? 8 : 10;
216 cutoff
= (unsigned long)ULONG_MAX
/ (unsigned long)base
;
217 cutlim
= (unsigned long)ULONG_MAX
% (unsigned long)base
;
218 for (acc
= 0, any
= 0;; c
= *s
++)
223 c
-= isupper(c
) ? 'A' - 10 : 'a' - 10;
228 if (any
< 0 || acc
> cutoff
|| (acc
== cutoff
&& c
> cutlim
))
243 *endptr
= any
? (char *)s
- 1 : (char *)nptr
;
249 strpbrk(const char* s
, const char* accept
)
252 for (; (*s
) != 0; s
++)
254 for (i
= 0; accept
[i
] != 0; i
++)
256 if (accept
[i
] == (*s
))
268 KdbpSafeReadMemory(PVOID dst
, PVOID src
, INT size
)
273 page_end
= (((ULONG_PTR
)src
+ size
) / PAGE_SIZE
);
274 for (page
= ((ULONG_PTR
)src
/ PAGE_SIZE
); page
<= page_end
; page
++)
276 if (!MmIsPagePresent(NULL
, (PVOID
)(page
* PAGE_SIZE
)))
277 return STATUS_UNSUCCESSFUL
;
281 RtlCopyMemory(dst
, src
, size
);
282 return STATUS_SUCCESS
;
287 KdbpSafeWriteMemory(PVOID dst
, PVOID src
, INT size
)
289 return KdbpSafeWriteMemory(dst
, src
, size
);
292 /* check destination */
293 page_end
= (((ULONG_PTR
)dst
+ size
) / PAGE_SIZE
);
294 for (page
= ((ULONG_PTR
)dst
/ PAGE_SIZE
); page
<= page_end
; page
++)
296 if (!MmIsPagePresent(NULL
, (PVOID
)(page
* PAGE_SIZE
)))
297 return STATUS_UNSUCCESSFUL
;
301 RtlCopyMemory(dst
, src
, size
);
302 return STATUS_SUCCESS
;
308 KdbGetCommand(PCH Buffer
)
312 static CHAR LastCommand
[256] = "";
314 static CHAR LastKey
= '\0';
316 KbdEchoOn
= !((KdDebugState
& KD_DEBUG_KDNOECHO
) != 0);
320 if (KdDebugState
& KD_DEBUG_KDSERIAL
)
321 while ((Key
= KdbTryGetCharSerial()) == -1);
323 while ((Key
= KdbTryGetCharKeyboard(&ScanCode
)) == -1);
325 if (Key
== '\n' && LastKey
== '\r')
327 /* Ignore this key... */
329 else if (Key
== '\r' || Key
== '\n')
333 Repeat the last command if the user presses enter. Reduces the
334 risk of RSI when single-stepping.
338 strcpy(Buffer
, LastCommand
);
343 strcpy(LastCommand
, Orig
);
348 else if (Key
== BS
|| Key
== DEL
)
355 DbgPrint("%c %c", BS
, BS
);
360 else if (ScanCode
== 72)
363 while (Buffer
> Orig
)
368 DbgPrint("%c %c", BS
, BS
);
372 for (i
= 0; LastCommand
[i
] != 0; i
++)
375 DbgPrint("%c", LastCommand
[i
]);
376 *Buffer
= LastCommand
[i
];
393 KdbDecodeAddress(PCHAR Buffer
, PULONG Address
)
395 while (isspace(*Buffer
))
399 if (Buffer
[0] == '<')
401 PCHAR ModuleName
= Buffer
+ 1;
402 PCHAR AddressString
= strpbrk(Buffer
, ":");
403 extern LIST_ENTRY ModuleTextListHead
;
404 PLIST_ENTRY current_entry
;
405 MODULE_TEXT_SECTION
* current
= NULL
;
406 static WCHAR ModuleNameW
[256];
409 if (AddressString
== NULL
)
411 DbgPrint("Address %x is malformed.\n", Buffer
);
416 while (isspace(*AddressString
))
421 for (i
= 0; ModuleName
[i
] != 0 && !isspace(ModuleName
[i
]); i
++)
423 ModuleNameW
[i
] = (WCHAR
)ModuleName
[i
];
427 /* Find the module. */
428 current_entry
= ModuleTextListHead
.Flink
;
430 while (current_entry
!= &ModuleTextListHead
&&
431 current_entry
!= NULL
)
434 CONTAINING_RECORD(current_entry
, MODULE_TEXT_SECTION
, ListEntry
);
435 if (wcscmp(ModuleNameW
, current
->Name
) == 0)
439 current_entry
= current_entry
->Flink
;
441 if (current_entry
== NULL
|| current_entry
== &ModuleTextListHead
)
443 DbgPrint("Couldn't find module %s.\n", ModuleName
);
446 *Address
= current
->Base
;
447 *Address
+= strtoul(AddressString
, NULL
, 16);
452 *Address
= strtoul(Buffer
, NULL
, 0);
458 KdbOverwriteInst(ULONG Address
, PUCHAR PreviousInst
, UCHAR NewInst
)
462 /* Get the protection for the address. */
463 Protect
= MmGetPageProtect(PsGetCurrentProcess(), (PVOID
)PAGE_ROUND_DOWN(Address
));
464 /* Return if that page isn't present. */
465 if (Protect
& PAGE_NOACCESS
)
467 return(STATUS_MEMORY_NOT_ALLOCATED
);
469 if (Protect
& (PAGE_READONLY
|PAGE_EXECUTE
|PAGE_EXECUTE_READ
))
471 MmSetPageProtect(PsGetCurrentProcess(), (PVOID
)PAGE_ROUND_DOWN(Address
),
472 (Protect
& ~(PAGE_READONLY
|PAGE_EXECUTE
|PAGE_EXECUTE_READ
)) | PAGE_READWRITE
);
474 /* Copy the old instruction back to the caller. */
475 if (PreviousInst
!= NULL
)
477 Status
= KdbpSafeReadMemory(PreviousInst
, (PUCHAR
)Address
, 1);
478 if (!NT_SUCCESS(Status
))
480 if (Protect
& (PAGE_READONLY
|PAGE_EXECUTE
|PAGE_EXECUTE_READ
))
482 MmSetPageProtect(PsGetCurrentProcess(), (PVOID
)PAGE_ROUND_DOWN(Address
), Protect
);
487 /* Copy the new instruction in its place. */
488 Status
= KdbpSafeWriteMemory((PUCHAR
)Address
, &NewInst
, 1);
489 if (Protect
& (PAGE_READONLY
|PAGE_EXECUTE
|PAGE_EXECUTE_READ
))
491 MmSetPageProtect(PsGetCurrentProcess(), (PVOID
)PAGE_ROUND_DOWN(Address
), Protect
);
498 KdbRenableBreakPoints(VOID
)
501 for (i
= 0; i
< KDB_MAXIMUM_BREAKPOINT_COUNT
; i
++)
503 if (KdbActiveBreakPoints
[i
].Assigned
&&
504 !KdbActiveBreakPoints
[i
].Enabled
)
506 KdbActiveBreakPoints
[i
].Enabled
= TRUE
;
507 (VOID
)KdbOverwriteInst(KdbActiveBreakPoints
[i
].Address
,
508 &KdbActiveBreakPoints
[i
].SavedInst
,
515 KdbIsBreakPointOurs(PKTRAP_FRAME Tf
)
518 for (i
= 0; i
< KDB_MAXIMUM_BREAKPOINT_COUNT
; i
++)
520 if (KdbActiveBreakPoints
[i
].Assigned
&&
521 KdbActiveBreakPoints
[i
].Address
== (Tf
->Eip
- 1))
530 KdbDeleteBreakPoint(ULONG BreakPointNr
)
532 KdbBreakPointCount
--;
533 KdbActiveBreakPoints
[BreakPointNr
].Assigned
= FALSE
;
537 KdbInsertBreakPoint(ULONG Address
, BOOLEAN Temporary
)
542 if (KdbBreakPointCount
== KDB_MAXIMUM_BREAKPOINT_COUNT
)
544 return(STATUS_UNSUCCESSFUL
);
546 for (i
= 0; i
< KDB_MAXIMUM_BREAKPOINT_COUNT
; i
++)
548 if (!KdbActiveBreakPoints
[i
].Assigned
)
553 Status
= KdbOverwriteInst(Address
, &SavedInst
, 0xCC);
554 if (!NT_SUCCESS(Status
))
558 KdbActiveBreakPoints
[i
].Assigned
= TRUE
;
559 KdbActiveBreakPoints
[i
].Enabled
= TRUE
;
560 KdbActiveBreakPoints
[i
].Address
= Address
;
561 KdbActiveBreakPoints
[i
].Temporary
= Temporary
;
562 KdbActiveBreakPoints
[i
].SavedInst
= SavedInst
;
563 return(STATUS_SUCCESS
);
567 DbgSetBreakPoint(ULONG Argc
, PCH Argv
[], PKTRAP_FRAME Tf
)
574 DbgPrint("Need an address to set the breakpoint at.\n");
577 /* Stitch the remaining arguments back into a single string. */
578 for (i
= 2; i
< Argc
; i
++)
582 if (!KdbDecodeAddress(Argv
[1], &Addr
))
586 DbgPrint("Setting breakpoint at 0x%X\n", Addr
);
587 if (!NT_SUCCESS(Status
= KdbInsertBreakPoint(Addr
, FALSE
)))
589 DbgPrint("Failed to set breakpoint (Status %X)\n", Status
);
595 DbgDeleteBreakPoint(ULONG Argc
, PCH Argv
[], PKTRAP_FRAME Tf
)
600 DbgPrint("Need a breakpoint number to delete.\n");
603 BreakPointNr
= strtoul(Argv
[1], NULL
, 10);
604 DbgPrint("Deleting breakpoint %d.\n", BreakPointNr
);
605 KdbDeleteBreakPoint(BreakPointNr
);
610 DbgSetMemoryBreakPoint(ULONG Argc
, PCH Argv
[], PKTRAP_FRAME Tf
)
614 ULONG Length
, Address
;
617 if (Argc
!= 2 && Argc
< 5)
619 DbgPrint("ba <0-3> <r|w|e> <1|2|4> <address>\n");
622 DebugRegNr
= strtoul(Argv
[1], NULL
, 10);
625 DbgPrint("Debug register number should be between 0 and 3.\n");
630 /* Clear the breakpoint. */
631 Tf
->Dr7
&= ~(0x3 << (DebugRegNr
* 2));
632 if ((Tf
->Dr7
& 0xFF) == 0)
635 If no breakpoints are enabled then
636 clear the exact match flags.
638 Tf
->Dr7
&= 0xFFFFFCFF;
642 BreakType
= Argv
[2][0];
643 if (BreakType
!= 'r' && BreakType
!= 'w' && BreakType
!= 'e')
645 DbgPrint("Access type to break on should be either 'r', 'w' or 'e'.\n");
648 Length
= strtoul(Argv
[3], NULL
, 10);
649 if (Length
!= 1 && Length
!= 2 && Length
!= 4)
651 DbgPrint("Length of the breakpoint should be one, two or four.\n");
654 if (Length
!= 1 && BreakType
== 'e')
656 DbgPrint("The length of an execution breakpoint should be one.\n");
659 /* Stitch the remaining arguments back into a single string. */
660 for (i
= 4; i
< Argc
; i
++)
664 if (!KdbDecodeAddress(Argv
[4], &Address
))
668 if ((Address
& (Length
- 1)) != 0)
670 DbgPrint("The breakpoint address should be aligned to a multiple of "
671 "the breakpoint length.\n");
675 /* Set the breakpoint address. */
678 case 0: Tf
->Dr0
= Address
; break;
679 case 1: Tf
->Dr1
= Address
; break;
680 case 2: Tf
->Dr2
= Address
; break;
681 case 3: Tf
->Dr3
= Address
; break;
683 /* Enable the breakpoint. */
684 Tf
->Dr7
|= (0x3 << (DebugRegNr
* 2));
685 /* Enable the exact match bits. */
686 Tf
->Dr7
|= 0x00000300;
687 /* Clear existing state. */
688 Tf
->Dr7
&= ~(0xF << (16 + (DebugRegNr
* 4)));
689 /* Set the breakpoint type. */
692 case 'r': Rw
= 3; break;
693 case 'w': Rw
= 1; break;
694 case 'e': Rw
= 0; break;
696 Tf
->Dr7
|= (Rw
<< (16 + (DebugRegNr
* 4)));
697 /* Set the breakpoint length. */
698 Tf
->Dr7
|= ((Length
- 1) << (18 + (DebugRegNr
* 4)));
704 DbgStep(ULONG Argc
, PCH Argv
[], PKTRAP_FRAME Tf
)
706 /* Set the single step flag and return to the interrupted code. */
707 Tf
->Eflags
|= (1 << 8);
708 KdbIgnoreNextSingleStep
= FALSE
;
709 KdbLastSingleStepFrom
= Tf
->Eip
;
714 DbgStepOver(ULONG Argc
, PCH Argv
[], PKTRAP_FRAME Tf
)
719 if (!NT_SUCCESS(KdbpSafeReadMemory(Mem
, (PVOID
)Tf
->Eip
, sizeof (Mem
))))
721 DbgPrint("Couldn't access memory at 0x%x\n", (UINT
)Tf
->Eip
);
726 /* Check if the current instruction is a call. */
727 while (Eip
[0] == 0x66 || Eip
[0] == 0x67)
731 if (Eip
[0] == 0xE8 || Eip
[0] == 0x9A || Eip
[0] == 0xF2 || Eip
[0] == 0xF3 ||
732 (Eip
[0] == 0xFF && (Eip
[1] & 0x38) == 0x10))
734 ULONG NextInst
= Tf
->Eip
+ KdbGetInstLength(Tf
->Eip
);
735 KdbLastSingleStepFrom
= Tf
->Eip
;
736 KdbInsertBreakPoint(NextInst
, TRUE
);
741 return(DbgStep(Argc
, Argv
, Tf
));
746 DbgFinish(ULONG Argc
, PCH Argv
[], PKTRAP_FRAME Tf
)
748 PULONG Ebp
= (PULONG
)Tf
->Ebp
;
751 PKTHREAD CurrentThread
;
753 /* Check that ebp points onto the stack. */
754 CurrentThread
= KeGetCurrentThread();
755 if (CurrentThread
== NULL
||
756 !(Ebp
>= (PULONG
)CurrentThread
->StackLimit
&&
757 Ebp
<= (PULONG
)CurrentThread
->StackBase
))
759 DbgPrint("This function doesn't appear to have a valid stack frame.\n");
763 /* Get the address of the caller. */
764 Status
= KdbpSafeReadMemory(&ReturnAddress
, Ebp
+ 1, sizeof(ULONG
));
765 if (!NT_SUCCESS(Status
))
767 DbgPrint("Memory access error (%X) while getting return address.\n",
772 /* Set a temporary breakpoint at that location. */
773 Status
= KdbInsertBreakPoint(ReturnAddress
, TRUE
);
774 if (!NT_SUCCESS(Status
))
776 DbgPrint("Couldn't set a temporary breakpoint at %X (Status %X)\n",
777 ReturnAddress
, Status
);
782 Otherwise start running again and with any luck we will break back into
783 the debugger when the current function returns.
789 DbgDisassemble(ULONG Argc
, PCH Argv
[], PKTRAP_FRAME Tf
)
795 /* Stitch the remaining arguments back into a single string. */
796 for (i
= 2; i
< Argc
; i
++)
800 if (!KdbDecodeAddress(Argv
[1], &Address
))
809 for (i
= 0; i
< 10; i
++)
811 if (!KdbSymPrintAddress((PVOID
)Address
))
813 DbgPrint("<%x>", Address
);
816 InstLen
= KdbDisassemble(Address
);
819 DbgPrint("<INVALID>\n");
830 DbgProcessHelpCommand(ULONG Argc
, PCH Argv
[], PKTRAP_FRAME Tf
)
834 DbgPrint("Kernel debugger commands:\n");
835 for (i
= 0; DebuggerCommands
[i
].Name
!= NULL
; i
++)
837 DbgPrint(" %s", DebuggerCommands
[i
].Syntax
);
838 len
= strlen(DebuggerCommands
[i
].Syntax
);
841 for (j
= 0; j
< 35 - len
; j
++)
846 DbgPrint(" - %s\n", DebuggerCommands
[i
].Help
);
852 DbgThreadListCommand(ULONG Argc
, PCH Argv
[], PKTRAP_FRAME Tf
)
855 if (Argc
== 2 && (!strcmp(Argv
[1], "sys") || !strcmp(Argv
[1], "SYS")))
858 PsDumpThreads(System
);
863 DbgProcessListCommand(ULONG Argc
, PCH Argv
[], PKTRAP_FRAME Tf
)
865 extern LIST_ENTRY PsActiveProcessHead
;
866 PLIST_ENTRY current_entry
;
870 if (PsActiveProcessHead
.Flink
== NULL
)
872 DbgPrint("No processes.\n");
876 DbgPrint("Process list: ");
877 current_entry
= PsActiveProcessHead
.Flink
;
878 while (current_entry
!= &PsActiveProcessHead
)
880 current
= CONTAINING_RECORD(current_entry
, EPROCESS
, ProcessListEntry
);
881 DbgPrint("%d %.8s", current
->UniqueProcessId
,
882 current
->ImageFileName
);
888 current_entry
= current_entry
->Flink
;
894 DbgPrintBackTrace(PULONG Frame
, ULONG_PTR StackBase
, ULONG_PTR StackLimit
)
898 DbgPrint("Frames:\n");
899 while (Frame
!= NULL
)
901 if (!NT_SUCCESS(KdbpSafeReadMemory(&Address
, Frame
+ 1, sizeof (Address
))))
903 DbgPrint("\nCouldn't access memory at 0x%x!\n", (UINT
)(Frame
+ 1));
906 KdbSymPrintAddress(Address
);
908 if (!NT_SUCCESS(KdbpSafeReadMemory(&Frame
, Frame
, sizeof (Frame
))))
910 DbgPrint("\nCouldn't access memory at 0x%x!\n", (UINT
)Frame
);
917 DbgAddrCommand(ULONG Argc
, PCH Argv
[], PKTRAP_FRAME tf
)
923 Addr
= (PVOID
)strtoul(Argv
[1], NULL
, 0);
924 KdbSymPrintAddress(Addr
);
931 DbgXCommand(ULONG Argc
, PCH Argv
[], PKTRAP_FRAME tf
)
939 Addr
= (PDWORD
)strtoul(Argv
[1], NULL
, 0);
941 Items
= (DWORD
)strtoul(Argv
[2], NULL
, 0);
946 for (i
= 0; i
< Items
; i
++)
952 DbgPrint("%08x:", (int)(&Addr
[i
]));
954 if (!NT_SUCCESS(KdbpSafeReadMemory(&Item
, Addr
+ i
, sizeof (Item
))))
956 DbgPrint("\nCouldn't access memory at 0x%x!\n", (UINT
)(Addr
+ i
));
959 DbgPrint("%08x ", Item
);
965 static int KjsReadRegValue( void *context
,
969 PVOID
*context_list
= context
;
970 PKJS kjs
= (PKJS
)context_list
[0];
971 JSVirtualMachine
*vm
= kjs
->vm
;
973 RTL_QUERY_REGISTRY_TABLE QueryTable
[2] = { { 0 } };
974 UNICODE_STRING NameString
;
975 UNICODE_STRING PathString
;
976 UNICODE_STRING DefaultString
;
977 UNICODE_STRING ValueResult
;
978 ANSI_STRING AnsiResult
;
980 if (args
->u
.vinteger
!= 2 ||
981 args
[1].type
!= JS_STRING
|| args
[2].type
!= JS_STRING
) {
982 return JS_PROPERTY_FOUND
;
985 RtlInitUnicodeString(&PathString
,NULL
);
986 RtlInitUnicodeString(&NameString
,NULL
);
988 cp
= js_string_to_c_string (vm
, &args
[1]);
989 RtlCreateUnicodeStringFromAsciiz(&PathString
,cp
);
991 cp
= js_string_to_c_string (vm
, &args
[2]);
992 RtlCreateUnicodeStringFromAsciiz(&NameString
,cp
);
995 RtlInitUnicodeString(&ValueResult
,NULL
);
996 RtlInitUnicodeString(&DefaultString
,L
"");
997 RtlInitAnsiString(&AnsiResult
,NULL
);
999 QueryTable
->EntryContext
= 0;
1001 RTL_QUERY_REGISTRY_REQUIRED
| RTL_QUERY_REGISTRY_DIRECT
;
1002 QueryTable
->Name
= NameString
.Buffer
;
1003 QueryTable
->DefaultType
= REG_SZ
;
1004 QueryTable
->DefaultData
= &DefaultString
;
1005 QueryTable
->EntryContext
= &ValueResult
;
1006 Status
= RtlQueryRegistryValues( RTL_REGISTRY_ABSOLUTE
,
1012 RtlFreeUnicodeString(&NameString
);
1013 RtlFreeUnicodeString(&PathString
);
1015 if (NT_SUCCESS(Status
)) {
1016 RtlInitAnsiString(&AnsiResult
,NULL
);
1017 RtlUnicodeStringToAnsiString(&AnsiResult
,
1020 js_vm_make_string (vm
, result
, AnsiResult
.Buffer
,
1021 strlen(AnsiResult
.Buffer
));
1022 RtlFreeAnsiString(&AnsiResult
);
1024 result
->type
= JS_INTEGER
;
1025 result
->u
.vinteger
= Status
;
1028 return JS_PROPERTY_FOUND
;
1031 static int KjsGetRegister( void *context
,
1034 PVOID
*context_list
= context
;
1035 if( args
->u
.vinteger
== 1 && args
->type
== JS_INTEGER
) {
1036 DWORD Result
= ((DWORD
*)context_list
[1])[args
[1].u
.vinteger
];
1037 result
->type
= JS_INTEGER
;
1038 result
->u
.vinteger
= Result
;
1041 return JS_PROPERTY_FOUND
;
1044 static int KjsGetNthModule( void *context
,
1047 PVOID
*context_list
= context
;
1048 PKJS kjs
= (PKJS
)context_list
[0];
1049 JSVirtualMachine
*vm
= kjs
->vm
;
1050 PLIST_ENTRY current_entry
;
1051 MODULE_TEXT_SECTION
*current
= NULL
;
1052 extern LIST_ENTRY ModuleTextListHead
;
1055 if (args
->u
.vinteger
!= 1 || args
[1].type
!= JS_INTEGER
) {
1056 return JS_PROPERTY_FOUND
;
1059 current_entry
= ModuleTextListHead
.Flink
;
1061 while (current_entry
!= &ModuleTextListHead
&&
1062 current_entry
!= NULL
&&
1063 n
<= args
[1].u
.vinteger
) {
1064 current
= CONTAINING_RECORD(current_entry
, MODULE_TEXT_SECTION
,
1066 current_entry
= current_entry
->Flink
;
1070 if (current_entry
&& current
) {
1071 ANSI_STRING NameStringNarrow
;
1072 UNICODE_STRING NameUnicodeString
;
1074 RtlInitUnicodeString( &NameUnicodeString
, current
->Name
);
1075 RtlUnicodeStringToAnsiString( &NameStringNarrow
,
1079 js_vm_make_array (vm
, result
, 2);
1081 js_vm_make_string (vm
,
1082 &result
->u
.varray
->data
[0],
1083 NameStringNarrow
.Buffer
,
1084 NameStringNarrow
.Length
);
1086 RtlFreeAnsiString(&NameStringNarrow
);
1088 result
->u
.varray
->data
[1].type
= JS_INTEGER
;
1089 result
->u
.varray
->data
[1].u
.vinteger
= (DWORD
)current
->Base
;
1090 result
->type
= JS_ARRAY
;
1091 return JS_PROPERTY_FOUND
;
1093 result
->type
= JS_UNDEFINED
;
1094 return JS_PROPERTY_FOUND
;
1097 static BOOL
FindJSEndMark( PCHAR Buffer
) {
1100 for( i
= 0; Buffer
[i
] && Buffer
[i
+1]; i
++ ) {
1101 if( Buffer
[i
] == ';' && Buffer
[i
+1] == ';' ) return TRUE
;
1107 DbgScriptCommand(ULONG Argc
, PCH Argv
[], PKTRAP_FRAME tf
)
1111 static void *interp
= 0;
1112 void *script_cmd_context
[2];
1114 if( !interp
) interp
= kjs_create_interp(NULL
);
1115 if( !interp
) return 1;
1117 BufferStart
= Buffer
= ExAllocatePool( NonPagedPool
, 4096 );
1118 if( !Buffer
) return 1;
1120 script_cmd_context
[0] = interp
;
1121 script_cmd_context
[1] = &tf
;
1123 kjs_system_register( interp
, "regs", script_cmd_context
,
1125 kjs_system_register( interp
, "regread", script_cmd_context
,
1127 kjs_system_register( interp
, "getmodule", script_cmd_context
,
1133 "'\\\\Registry\\\\Machine\\\\System\\\\"
1134 "CurrentControlSet\\\\Control\\\\Kdb',"
1137 DbgPrint("\nKernel Debugger Script Interface (JavaScript :-)\n");
1138 DbgPrint("Terminate input with ;; and end scripting with .\n");
1141 if( Buffer
!= BufferStart
)
1145 KdbGetCommand( BufferStart
);
1146 if( BufferStart
[0] == '.' ) {
1147 if( BufferStart
!= Buffer
) {
1148 DbgPrint("Input Aborted.\n");
1149 BufferStart
= Buffer
;
1151 /* Single dot input -> exit */
1155 if( FindJSEndMark( Buffer
) ) {
1156 kjs_eval( interp
, Buffer
);
1157 BufferStart
= Buffer
;
1160 BufferStart
= BufferStart
+ strlen(BufferStart
);
1165 ExFreePool( Buffer
);
1167 kjs_system_unregister( interp
, script_cmd_context
, KjsGetRegister
);
1168 kjs_system_unregister( interp
, script_cmd_context
, KjsReadRegValue
);
1169 kjs_system_unregister( interp
, script_cmd_context
, KjsGetNthModule
);
1175 DbgBackTraceCommand(ULONG Argc
, PCH Argv
[], PKTRAP_FRAME Tf
)
1177 ULONG_PTR StackBase
, StackLimit
;
1178 extern unsigned int init_stack
, init_stack_top
;
1180 /* Without an argument we print the current stack. */
1183 if (PsGetCurrentThread() != NULL
)
1185 StackBase
= (ULONG_PTR
)PsGetCurrentThread()->Tcb
.StackBase
;
1186 StackLimit
= PsGetCurrentThread()->Tcb
.StackLimit
;
1190 StackBase
= (ULONG_PTR
)init_stack_top
;
1191 StackLimit
= (ULONG_PTR
)init_stack
;
1193 DbgPrintBackTrace((PULONG
)&Tf
->DebugEbp
, StackBase
, StackLimit
);
1196 * If there are two arguments and the second begins with a asterik treat it
1197 * as the address of a frame to start printing the back trace from.
1199 else if (Argc
== 2 && Argv
[1][0] == '*')
1202 Frame
= (PULONG
)strtoul(&Argv
[1][1], NULL
, 0);
1203 DbgPrintBackTrace(Frame
, ULONG_MAX
, 0);
1206 * Otherwise treat the argument as the id of a thread whose back trace is to
1216 DbgPrintCr0(ULONG Cr0
)
1237 if (!(Cr0
& (1 << 4)))
1245 for (i
= 6; i
< 16; i
++)
1249 DbgPrint(" BIT%d", i
);
1252 if (Cr0
& (1 << 16))
1256 if (Cr0
& (1 << 17))
1260 if (Cr0
& (1 << 18))
1264 for (i
= 19; i
< 29; i
++)
1268 DbgPrint(" BIT%d", i
);
1271 if (Cr0
& (1 << 29))
1275 if (Cr0
& (1 << 30))
1279 if (Cr0
& (1 << 31))
1287 DbgCRegsCommand(ULONG Argc
, PCH Argv
[], PKTRAP_FRAME Tf
)
1289 ULONG Cr0
, Cr1
, Cr2
, Cr3
, Cr4
;
1293 __asm__
__volatile__ ("movl %%cr0, %0\n\t" : "=d" (Cr0
));
1294 /* __asm__ __volatile__ ("movl %%cr1, %0\n\t" : "=d" (Cr1)); */
1296 __asm__
__volatile__ ("movl %%cr2, %0\n\t" : "=d" (Cr2
));
1297 __asm__
__volatile__ ("movl %%cr3, %0\n\t" : "=d" (Cr3
));
1298 __asm__
__volatile__ ("movl %%cr4, %0\n\t" : "=d" (Cr4
));
1299 __asm__
__volatile__ ("str %0\n\t" : "=d" (Tr
));
1300 __asm__
__volatile__ ("sldt %0\n\t" : "=d" (Ldtr
));
1302 DbgPrint("CR1 %.8x CR2 %.8x CR3 %.8x CR4 %.8x TR %.8x LDTR %.8x\n",
1303 Cr1
, Cr2
, Cr3
, Cr4
, (ULONG
)Tf
, Ldtr
);
1308 DbgDRegsCommand(ULONG Argc
, PCH Argv
[], PKTRAP_FRAME Tf
)
1310 DbgPrint("Trap : DR0 %.8x DR1 %.8x DR2 %.8x DR3 %.8x DR6 %.8x DR7 %.8x\n",
1311 Tf
->Dr0
, Tf
->Dr1
, Tf
->Dr2
, Tf
->Dr3
, Tf
->Dr6
, Tf
->Dr7
);
1316 DbgContCommand(ULONG Argc
, PCH Argv
[], PKTRAP_FRAME Tf
)
1318 /* Not too difficult. */
1323 DbgStopCondition(ULONG Argc
, PCH Argv
[], PKTRAP_FRAME Tf
)
1326 if( KdbHandleHandled
) DbgPrint("all\n");
1327 else if( KdbHandleUmode
) DbgPrint("umode\n");
1328 else DbgPrint("kmode\n");
1330 else if( !strcmp(Argv
[1],"all") )
1331 { KdbHandleHandled
= TRUE
; KdbHandleUmode
= TRUE
; }
1332 else if( !strcmp(Argv
[1],"umode") )
1333 { KdbHandleHandled
= FALSE
; KdbHandleUmode
= TRUE
; }
1334 else if( !strcmp(Argv
[1],"kmode") )
1335 { KdbHandleHandled
= FALSE
; KdbHandleUmode
= FALSE
; }
1341 DbgModuleLoadedAction(ULONG Argc
, PCH Argv
[], PKTRAP_FRAME Tf
)
1345 if (KdbBreakOnModuleLoad
)
1346 DbgPrint("Current setting: break\n");
1348 DbgPrint("Current setting: continue\n");
1350 else if (!strcmp(Argv
[1], "break"))
1352 KdbBreakOnModuleLoad
= TRUE
;
1354 else if (!strcmp(Argv
[1], "continue"))
1356 KdbBreakOnModuleLoad
= FALSE
;
1360 DbgPrint("Unknown setting: %s\n", Argv
[1]);
1367 DbgEchoToggle(ULONG Argc
, PCH Argv
[], PKTRAP_FRAME Tf
)
1369 KbdEchoOn
= !KbdEchoOn
;
1374 DbgPrintEflags(ULONG Eflags
)
1376 DbgPrint("EFLAGS:");
1377 if (Eflags
& (1 << 0))
1381 if (!(Eflags
& (1 << 1)))
1385 if (Eflags
& (1 << 2))
1389 if (Eflags
& (1 << 3))
1393 if (Eflags
& (1 << 4))
1397 if (Eflags
& (1 << 5))
1401 if (Eflags
& (1 << 6))
1405 if (Eflags
& (1 << 7))
1409 if (Eflags
& (1 << 8))
1413 if (Eflags
& (1 << 9))
1417 if (Eflags
& (1 << 10))
1421 if (Eflags
& (1 << 11))
1425 if ((Eflags
& ((1 << 12) | (1 << 13))) == 0)
1429 else if ((Eflags
& ((1 << 12) | (1 << 13))) == 1)
1433 else if ((Eflags
& ((1 << 12) | (1 << 13))) == 2)
1437 else if ((Eflags
& ((1 << 12) | (1 << 13))) == 3)
1441 if (Eflags
& (1 << 14))
1445 if (Eflags
& (1 << 15))
1449 if (Eflags
& (1 << 16))
1453 if (Eflags
& (1 << 17))
1457 if (Eflags
& (1 << 18))
1461 if (Eflags
& (1 << 19))
1465 if (Eflags
& (1 << 20))
1469 if (Eflags
& (1 << 21))
1473 if (Eflags
& (1 << 22))
1477 if (Eflags
& (1 << 23))
1481 if (Eflags
& (1 << 24))
1485 if (Eflags
& (1 << 25))
1489 if (Eflags
& (1 << 26))
1493 if (Eflags
& (1 << 27))
1497 if (Eflags
& (1 << 28))
1501 if (Eflags
& (1 << 29))
1505 if (Eflags
& (1 << 30))
1509 if (Eflags
& (1 << 31))
1517 DbgRegsCommand(ULONG Argc
, PCH Argv
[], PKTRAP_FRAME Tf
)
1519 DbgPrint("CS:EIP %.4x:%.8x, EAX %.8x EBX %.8x ECX %.8x EDX %.8x\n",
1520 Tf
->Cs
& 0xFFFF, Tf
->Eip
, Tf
->Eax
, Tf
->Ebx
, Tf
->Ecx
, Tf
->Edx
);
1521 DbgPrint("ESI %.8x EDI %.8x EBP %.8x SS:ESP %.4x:%.8x\n",
1522 Tf
->Esi
, Tf
->Edi
, Tf
->Ebp
, Tf
->Ss
& 0xFFFF, Tf
->Esp
);
1523 DbgPrintEflags(Tf
->Eflags
);
1528 DbgBugCheckCommand(ULONG Argc
, PCH Argv
[], PKTRAP_FRAME Tf
)
1530 KEBUGCHECK(0xDEADDEAD);
1535 DbgShowFilesCommand(ULONG Argc
, PCH Argv
[], PKTRAP_FRAME Tf
)
1542 DbgEnableFileCommand(ULONG Argc
, PCH Argv
[], PKTRAP_FRAME Tf
)
1546 if (strlen(Argv
[1]) > 0)
1548 DbgEnableFile(Argv
[1]);
1555 DbgDisableFileCommand(ULONG Argc
, PCH Argv
[], PKTRAP_FRAME Tf
)
1559 if (strlen(Argv
[1]) > 0)
1561 DbgDisableFile(Argv
[1]);
1568 KdbCreateThreadHook(PCONTEXT Context
)
1570 Context
->Dr0
= x_dr0
;
1571 Context
->Dr1
= x_dr1
;
1572 Context
->Dr2
= x_dr2
;
1573 Context
->Dr3
= x_dr3
;
1574 Context
->Dr7
= x_dr7
;
1578 KdbDoCommand(PCH CommandLine
, PKTRAP_FRAME Tf
)
1583 static PCH Argv
[256];
1585 static CHAR OrigCommand
[256];
1587 strcpy(OrigCommand
, CommandLine
);
1591 while ((s1
= strpbrk(s
, "\t ")) != NULL
)
1601 for (i
= 0; DebuggerCommands
[i
].Name
!= NULL
; i
++)
1603 if (strcmp(DebuggerCommands
[i
].Name
, Argv
[0]) == 0)
1605 return(DebuggerCommands
[i
].Fn(Argc
, Argv
, Tf
));
1608 DbgPrint("Command '%s' is unknown.", OrigCommand
);
1613 KdbMainLoop(PKTRAP_FRAME Tf
)
1618 if (!KdbEnteredOnSingleStep
)
1620 DbgPrint("\nEntered kernel debugger (type \"help\" for a list of commands)\n");
1624 if (!KdbSymPrintAddress((PVOID
)Tf
->Eip
))
1626 DbgPrint("<%x>", Tf
->Eip
);
1629 if (KdbDisassemble(Tf
->Eip
) < 0)
1631 DbgPrint("<INVALID>");
1633 KdbEnteredOnSingleStep
= FALSE
;
1634 KdbLastSingleStepFrom
= 0xFFFFFFFF;
1639 DbgPrint("\nkdb:> ");
1641 KdbGetCommand(Command
);
1642 s
= KdbDoCommand(Command
, Tf
);
1647 KdbInternalEnter(PKTRAP_FRAME Tf
)
1649 __asm__
__volatile__ ("cli\n\t");
1651 if (KdDebugState
& KD_DEBUG_SCREEN
)
1653 HalReleaseDisplayOwnership();
1655 (VOID
)KdbMainLoop(Tf
);
1657 __asm__
__volatile__("sti\n\t");
1661 KdbEnterDebuggerException(PEXCEPTION_RECORD ExceptionRecord
,
1662 KPROCESSOR_MODE PreviousMode
,
1664 PKTRAP_FRAME TrapFrame
,
1665 BOOLEAN AlwaysHandle
)
1668 ULONG ExpNr
= (ULONG
)TrapFrame
->DebugArgMark
;
1670 /* Always handle beakpoints */
1671 if (ExpNr
!= 1 && ExpNr
!= 3)
1673 DbgPrint(":KDBG:Entered:%s:%s\n",
1674 PreviousMode
==KernelMode
? "kmode" : "umode",
1675 AlwaysHandle
? "always" : "if-unhandled");
1677 /* If we aren't handling umode exceptions then return */
1678 if (PreviousMode
== UserMode
&& !KdbHandleUmode
&& !AlwaysHandle
)
1680 return kdHandleException
;
1683 /* If the exception would be unhandled (and we care) then handle it */
1684 if (PreviousMode
== KernelMode
&& !KdbHandleHandled
&& !AlwaysHandle
)
1686 return kdHandleException
;
1690 /* Exception inside the debugger? Game over. */
1691 if (KdbEntryCount
> 0)
1693 return(kdHandleException
);
1697 /* Clear the single step flag. */
1698 TrapFrame
->Eflags
&= ~(1 << 8);
1700 Reenable any breakpoints we disabled so we could execute the breakpointed
1703 KdbRenableBreakPoints();
1704 /* Silently ignore a debugger initiated single step. */
1705 if (ExpNr
== 1 && KdbIgnoreNextSingleStep
)
1707 KdbIgnoreNextSingleStep
= FALSE
;
1711 /* If we stopped on one of our breakpoints then let the user know. */
1712 if (ExpNr
== 3 && (BreakPointNr
= KdbIsBreakPointOurs(TrapFrame
)) >= 0)
1714 DbgPrint("Entered debugger on breakpoint %d.\n", BreakPointNr
);
1716 The breakpoint will point to the next instruction by default so
1717 point it back to the start of original instruction.
1721 ..and restore the original instruction.
1723 (VOID
)KdbOverwriteInst(TrapFrame
->Eip
, NULL
,
1724 KdbActiveBreakPoints
[BreakPointNr
].SavedInst
);
1726 If this was a breakpoint set by the debugger then delete it otherwise
1727 flag to enable it again after we step over this instruction.
1729 if (KdbActiveBreakPoints
[BreakPointNr
].Temporary
)
1731 KdbActiveBreakPoints
[BreakPointNr
].Assigned
= FALSE
;
1732 KdbBreakPointCount
--;
1733 KdbEnteredOnSingleStep
= TRUE
;
1737 KdbActiveBreakPoints
[BreakPointNr
].Enabled
= FALSE
;
1738 TrapFrame
->Eflags
|= (1 << 8);
1739 KdbIgnoreNextSingleStep
= TRUE
;
1742 else if (ExpNr
== 1)
1744 if ((TrapFrame
->Dr6
& 0xF) != 0)
1746 DbgPrint("Entered debugger on memory breakpoint(s) %s%s%s%s.\n",
1747 (TrapFrame
->Dr6
& 0x1) ? "1" : "",
1748 (TrapFrame
->Dr6
& 0x2) ? "2" : "",
1749 (TrapFrame
->Dr6
& 0x4) ? "3" : "",
1750 (TrapFrame
->Dr6
& 0x8) ? "4" : "");
1752 else if (KdbLastSingleStepFrom
!= 0xFFFFFFFF)
1754 KdbEnteredOnSingleStep
= TRUE
;
1758 DbgPrint("Entered debugger on unexpected debug trap.\n");
1763 const char *ExceptionString
=
1764 (ExpNr
< (sizeof (ExceptionTypeStrings
) / sizeof (ExceptionTypeStrings
[0]))) ?
1765 (ExceptionTypeStrings
[ExpNr
]) :
1766 ("Unknown/User defined exception");
1767 DbgPrint("Entered debugger on exception number %d (%s)\n", ExpNr
, ExceptionString
);
1769 KdbInternalEnter(TrapFrame
);
1771 if (ExpNr
!= 1 && ExpNr
!= 3)
1773 return(kdHandleException
);
1777 /* Clear dr6 status flags. */
1778 TrapFrame
->Dr6
&= 0xFFFF1F00;
1779 /* Set the RF flag to we don't trigger the same breakpoint again. */
1782 TrapFrame
->Eflags
|= (1 << 16);
1789 KdbModuleLoaded(IN PUNICODE_STRING Name
)
1791 if (!KdbBreakOnModuleLoad
)
1794 DbgPrint("Module %wZ loaded.\n", Name
);
1795 DbgBreakPointWithStatus(DBG_STATUS_CONTROL_C
);