1 /****************************************************************************
3 THIS SOFTWARE IS NOT COPYRIGHTED
5 HP offers the following for use in the public domain. HP makes no
6 warranty with regard to the software or it's performance and the
7 user accepts the software "AS IS" with all faults.
9 HP DISCLAIMS ANY WARRANTIES, EXPRESS OR IMPLIED, WITH REGARD
10 TO THIS SOFTWARE INCLUDING BUT NOT LIMITED TO THE WARRANTIES
11 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
13 ****************************************************************************/
14 /****************************************************************************
15 * Contributor: Lake Stevens Instrument Division$
17 * Description: low level support for gdb debugger. $
19 * Written by: Glenn Engel $
20 * ModuleState: Experimental $
22 * Modified for 386 by Jim Kingdon, Cygnus Support.
23 * Modified for ReactOS by Casper S. Hornstrup <chorns@users.sourceforge.net>
25 ****************************************************************************/
31 /************************************************************************/
33 static BOOLEAN GspInitialized
;
34 static BOOLEAN GspRemoteDebug
;
36 static CONST CHAR HexChars
[] = "0123456789abcdef";
38 static PETHREAD GspRunThread
; /* NULL means run all threads */
39 static PETHREAD GspDbgThread
;
40 static PETHREAD GspEnumThread
;
42 static FAST_MUTEX GspLock
;
44 extern LIST_ENTRY PsActiveProcessHead
;
46 /* FIXME hardcoded for COM2, 115200 baud */
47 ULONG GdbPortNumber
= DEFAULT_DEBUG_PORT
;
48 CPPORT GdbPortInfo
= {0, DEFAULT_DEBUG_BAUD_RATE
, 0};
50 static CHAR GspInBuffer
[1000];
51 static CHAR GspOutBuffer
[1000];
53 /* Number of Registers. */
58 EAX
, ECX
, EDX
, EBX
, ESP
, EBP
, ESI
, EDI
,
59 PC
/* also known as eip */ ,
60 PS
/* also known as eflags */ ,
61 CS
, SS
, DS
, ES
, FS
, GS
64 typedef struct _CPU_REGISTER
68 ULONG OffsetInContext
;
70 } CPU_REGISTER
, *PCPU_REGISTER
;
72 static CPU_REGISTER GspRegisters
[NUMREGS
] =
74 { 4, FIELD_OFFSET(KTRAP_FRAME
, Eax
), FIELD_OFFSET(CONTEXT
, Eax
), TRUE
},
75 { 4, FIELD_OFFSET(KTRAP_FRAME
, Ecx
), FIELD_OFFSET(CONTEXT
, Ecx
), TRUE
},
76 { 4, FIELD_OFFSET(KTRAP_FRAME
, Edx
), FIELD_OFFSET(CONTEXT
, Edx
), FALSE
},
77 { 4, FIELD_OFFSET(KTRAP_FRAME
, Ebx
), FIELD_OFFSET(CONTEXT
, Ebx
), TRUE
},
78 { 4, FIELD_OFFSET(KTRAP_FRAME
, HardwareEsp
), FIELD_OFFSET(CONTEXT
, Esp
), TRUE
},
79 { 4, FIELD_OFFSET(KTRAP_FRAME
, DbgEbp
), FIELD_OFFSET(CONTEXT
, Ebp
), TRUE
},
80 { 4, FIELD_OFFSET(KTRAP_FRAME
, Esi
), FIELD_OFFSET(CONTEXT
, Esi
), TRUE
},
81 { 4, FIELD_OFFSET(KTRAP_FRAME
, Edi
), FIELD_OFFSET(CONTEXT
, Edi
), TRUE
},
82 { 4, FIELD_OFFSET(KTRAP_FRAME
, DbgEip
), FIELD_OFFSET(CONTEXT
, Eip
), TRUE
},
83 { 4, FIELD_OFFSET(KTRAP_FRAME
, EFlags
), FIELD_OFFSET(CONTEXT
, EFlags
), TRUE
},
84 { 4, FIELD_OFFSET(KTRAP_FRAME
, SegCs
), FIELD_OFFSET(CONTEXT
, SegCs
), TRUE
},
85 { 4, FIELD_OFFSET(KTRAP_FRAME
, HardwareSegSs
), FIELD_OFFSET(CONTEXT
, SegSs
), TRUE
},
86 { 4, FIELD_OFFSET(KTRAP_FRAME
, SegDs
), FIELD_OFFSET(CONTEXT
, SegDs
), TRUE
},
87 { 4, FIELD_OFFSET(KTRAP_FRAME
, SegEs
), FIELD_OFFSET(CONTEXT
, SegEs
), TRUE
},
88 { 4, FIELD_OFFSET(KTRAP_FRAME
, SegFs
), FIELD_OFFSET(CONTEXT
, SegFs
), TRUE
},
89 { 4, FIELD_OFFSET(KTRAP_FRAME
, SegGs
), FIELD_OFFSET(CONTEXT
, SegGs
), TRUE
}
92 static PCHAR GspThreadStates
[DeferredReady
+ 1] =
107 if ((ch
>= '0') && (ch
<= '9'))
110 if ((ch
>= 'a') && (ch
<= 'f'))
111 return (ch
- 'a' + 10);
113 if ((ch
>= 'A') && (ch
<= 'F'))
114 return (ch
- 'A' + 10);
120 GdbPutChar(UCHAR Value
)
122 KdPortPutByteEx(&GdbPortInfo
, Value
);
130 while (!KdPortGetByteEx(&GdbPortInfo
, &Value
)) ;
134 /* scan for the sequence $<data>#<Checksum> */
138 PCHAR Buffer
= &GspInBuffer
[0];
146 /* wait around for the start character, ignore all other characters */
147 while ((ch
= GdbGetChar()) != '$') ;
154 /* now, read until a # or end of Buffer is found */
155 while (Count
< sizeof(GspInBuffer
) - 1)
164 Checksum
= Checksum
+ ch
;
173 XmitChecksum
= (CHAR
)(HexValue(ch
) << 4);
175 XmitChecksum
+= (CHAR
)(HexValue(ch
));
177 if (Checksum
!= XmitChecksum
)
179 GdbPutChar('-'); /* failed checksum */
183 GdbPutChar('+'); /* successful transfer */
190 /* send the packet in Buffer. */
192 GspPutPacket(PCHAR Buffer
)
198 /* $<packet info>#<Checksum>. */
205 while ((ch
= Buffer
[Count
]))
213 GdbPutChar(HexChars
[(Checksum
>> 4) & 0xf]);
214 GdbPutChar(HexChars
[Checksum
& 0xf]);
216 while (GdbGetChar() != '+');
220 GspPutPacketNoWait(PCHAR Buffer
)
226 /* $<packet info>#<Checksum>. */
231 while ((ch
= Buffer
[Count
]))
239 GdbPutChar(HexChars
[(Checksum
>> 4) & 0xf]);
240 GdbPutChar(HexChars
[Checksum
& 0xf]);
243 /* Indicate to caller of GspMem2Hex or GspHex2Mem that there has been an error. */
244 static volatile BOOLEAN GspMemoryError
= FALSE
;
247 GspReadMemSafe(PCHAR Address
)
251 if (!KdpSafeReadMemory((ULONG_PTR
)Address
, 1, &ch
))
252 GspMemoryError
= TRUE
;
258 GspWriteMemSafe(PCHAR Address
, CHAR Ch
)
260 if (!KdpSafeWriteMemory((ULONG_PTR
)Address
, 1, Ch
))
261 GspMemoryError
= TRUE
;
264 /* Convert the memory pointed to by Address into hex, placing result in Buffer
265 * Return a pointer to the last char put in Buffer (null)
266 * If MayFault is TRUE, then we should set GspMemoryError in response to
267 * a fault; if FALSE treat a fault like any other fault in the stub.
270 GspMem2Hex(PCHAR Address
, PCHAR Buffer
, LONG Count
, BOOLEAN MayFault
)
275 for (i
= 0; i
< (ULONG
)Count
; i
++)
279 ch
= GspReadMemSafe(Address
);
287 *Buffer
++ = HexChars
[(ch
>> 4) & 0xf];
288 *Buffer
++ = HexChars
[ch
& 0xf];
297 GspWriteMem(PCHAR Address
, ULONG Count
, BOOLEAN MayFault
,
298 CHAR (*GetContent
)(PVOID Context
, ULONG Offset
), PVOID Context
)
307 while (Current
< Address
+ Count
)
309 Page
= (PCHAR
)PAGE_ROUND_DOWN(Current
);
310 if (Address
+ Count
<= Page
+ PAGE_SIZE
)
312 /* Fits in this page */
317 /* Flows into next page, handle only current page in this iteration */
318 CountInPage
= PAGE_SIZE
- (Address
- Page
);
321 for (i
= 0; i
< CountInPage
&& !GspMemoryError
; i
++)
323 ch
= (*GetContent
)(Context
, Current
- Address
);
326 GspWriteMemSafe(Current
, ch
);
335 return Current
- Address
;
339 return Current
- Address
;
343 GspHex2MemGetContent(PVOID Context
, ULONG Offset
)
345 return (CHAR
)((HexValue(*((PCHAR
)Context
+ 2 * Offset
)) << 4) +
346 HexValue(*((PCHAR
)Context
+ 2 * Offset
+ 1)));
349 /* Convert the hex array pointed to by Buffer into binary to be placed at Address
350 * Return a pointer to the character AFTER the last byte read from Buffer */
352 GspHex2Mem(PCHAR Buffer
, PCHAR Address
, ULONG Count
, BOOLEAN MayFault
)
354 Count
= GspWriteMem(Address
, Count
, MayFault
, GspHex2MemGetContent
, Buffer
);
355 return Buffer
+ 2 * Count
;
358 /**********************************************/
359 /* WHILE WE FIND NICE HEX CHARS, BUILD A LONG */
360 /* RETURN NUMBER OF CHARS PROCESSED */
361 /**********************************************/
363 GspHex2Long(PCHAR
*Address
, PLONG Value
)
372 Hex
= HexValue(**Address
);
375 *Value
= (*Value
<< 4) | Hex
;
390 GspLong2Hex(PCHAR
*Address
, LONG Value
)
394 Save
= (((Value
>> 0) & 0xff) << 24) | (((Value
>> 8) & 0xff) << 16) |
395 (((Value
>> 16) & 0xff) << 8) | (((Value
>> 24) & 0xff) << 0);
397 *Address
= GspMem2Hex((PCHAR
)&Save
, *Address
, 4, FALSE
);
401 * When coming from kernel mode, Esp is not stored in the trap frame.
402 * Instead, it was pointing to the location of the TrapFrame Esp member
403 * when the exception occured. When coming from user mode, Esp is just
404 * stored in the TrapFrame Esp member.
407 GspGetEspFromTrapFrame(PKTRAP_FRAME TrapFrame
)
409 return KeGetPreviousMode() == KernelMode
?
410 (LONG
)&TrapFrame
->HardwareEsp
: (LONG
)TrapFrame
->HardwareEsp
;
414 GspGetRegisters(PCHAR Address
, PKTRAP_FRAME TrapFrame
)
420 ULONG_PTR
*KernelStack
;
422 if (NULL
== GspDbgThread
)
424 Thread
= PsGetCurrentThread();
428 TrapFrame
= GspDbgThread
->Tcb
.TrapFrame
;
429 Thread
= GspDbgThread
;
432 if (Waiting
== Thread
->Tcb
.State
)
434 KernelStack
= Thread
->Tcb
.KernelStack
;
435 for (i
= 0; i
< sizeof(GspRegisters
) / sizeof(GspRegisters
[0]); i
++)
440 Value
= KernelStack
[3];
443 Value
= KernelStack
[4];
446 Value
= KernelStack
[5];
449 Value
= KernelStack
[6];
452 Value
= KernelStack
[7];
455 Value
= (ULONG_PTR
)(KernelStack
+ 8);
458 Value
= KGDT_R0_CODE
;
461 Value
= KGDT_R0_DATA
;
468 Address
= GspMem2Hex((PCHAR
)&Value
, Address
, GspRegisters
[i
].Size
, FALSE
);
473 for (i
= 0; i
< sizeof(GspRegisters
) / sizeof(GspRegisters
[0]); i
++)
479 Value
= GspGetEspFromTrapFrame(TrapFrame
);
483 p
= (PULONG
)((ULONG_PTR
)TrapFrame
+ GspRegisters
[i
].OffsetInTF
);
490 * This thread has not been sheduled yet so assume it
491 * is still in PsBeginThreadWithContextInternal().
493 Value
= (ULONG
)KiThreadStartup
;
500 Address
= GspMem2Hex((PCHAR
)&Value
, Address
, GspRegisters
[i
].Size
, FALSE
);
506 GspSetRegistersInTrapFrame(PCHAR Address
, PCONTEXT Context
, PKTRAP_FRAME TrapFrame
)
517 for (i
= 0; i
< NUMREGS
; i
++)
519 if (GspRegisters
[i
].SetInContext
)
521 p
= (PULONG
)((ULONG_PTR
)Context
+ GspRegisters
[i
].OffsetInContext
);
525 p
= (PULONG
)((ULONG_PTR
)TrapFrame
+ GspRegisters
[i
].OffsetInTF
);
529 Buffer
= GspHex2Mem(Buffer
, (PCHAR
)&Value
, GspRegisters
[i
].Size
, FALSE
);
535 GspSetSingleRegisterInTrapFrame(PCHAR Address
, LONG Number
, PCONTEXT Context
, PKTRAP_FRAME TrapFrame
)
543 if (GspRegisters
[Number
].SetInContext
)
545 p
= (PULONG
)((ULONG_PTR
)Context
+ GspRegisters
[Number
].OffsetInContext
);
549 p
= (PULONG
)((ULONG_PTR
)TrapFrame
+ GspRegisters
[Number
].OffsetInTF
);
553 GspHex2Mem(Address
, (PCHAR
)&Value
, GspRegisters
[Number
].Size
, FALSE
);
558 GspFindThread(PCHAR Data
, PETHREAD
*Thread
)
560 PETHREAD ThreadInfo
= NULL
;
562 if (strcmp(Data
, "-1") == 0)
571 PCHAR ptr
= &Data
[0];
573 GspHex2Long(&ptr
, (PLONG
)&uThreadId
);
574 ThreadId
= (HANDLE
)uThreadId
;
576 if (!NT_SUCCESS(PsLookupThreadByThreadId(ThreadId
, &ThreadInfo
)))
583 *Thread
= ThreadInfo
;
588 GspSetThread(PCHAR Request
)
591 PCHAR ptr
= &Request
[1];
595 case 'c': /* Run thread */
596 if (GspFindThread(ptr
, &ThreadInfo
))
598 GspOutBuffer
[0] = 'O';
599 GspOutBuffer
[1] = 'K';
601 if (NULL
!= GspRunThread
)
602 ObDereferenceObject(GspRunThread
);
604 GspRunThread
= ThreadInfo
;
606 if (NULL
!= GspRunThread
)
607 ObReferenceObject(GspRunThread
);
611 GspOutBuffer
[0] = 'E';
615 case 'g': /* Debug thread */
616 if (GspFindThread(ptr
, &ThreadInfo
))
618 GspOutBuffer
[0] = 'O';
619 GspOutBuffer
[1] = 'K';
621 if (NULL
!= GspDbgThread
)
622 ObDereferenceObject(GspDbgThread
);
624 if (ThreadInfo
== PsGetCurrentThread())
627 ObDereferenceObject(ThreadInfo
);
631 GspDbgThread
= ThreadInfo
;
636 GspOutBuffer
[0] = 'E';
646 GspQuery(PCHAR Request
)
650 if (strncmp(Request
, "C", 1) == 0)
652 PCHAR ptr
= &GspOutBuffer
[2];
654 /* Get current thread id */
655 GspOutBuffer
[0] = 'Q';
656 GspOutBuffer
[1] = 'C';
658 if (NULL
!= GspDbgThread
)
659 Value
= (ULONG
)GspDbgThread
->Cid
.UniqueThread
;
661 Value
= (ULONG
)PsGetCurrentThread()->Cid
.UniqueThread
;
663 GspLong2Hex(&ptr
, Value
);
665 else if (strncmp(Request
, "fThreadInfo", 11) == 0)
668 PLIST_ENTRY AThread
, AProcess
;
669 PCHAR ptr
= &GspOutBuffer
[1];
671 /* Get first thread id */
672 GspEnumThread
= NULL
;
673 AProcess
= PsActiveProcessHead
.Flink
;
674 while (AProcess
!= &PsActiveProcessHead
)
676 Process
= CONTAINING_RECORD(AProcess
, EPROCESS
, ActiveProcessLinks
);
677 AThread
= Process
->ThreadListHead
.Flink
;
678 if (AThread
!= &Process
->ThreadListHead
)
680 GspEnumThread
= CONTAINING_RECORD(Process
->ThreadListHead
.Flink
,
681 ETHREAD
, ThreadListEntry
);
684 AProcess
= AProcess
->Flink
;
686 if (GspEnumThread
!= NULL
)
688 GspOutBuffer
[0] = 'm';
689 Value
= (ULONG
)GspEnumThread
->Cid
.UniqueThread
;
690 GspLong2Hex(&ptr
, Value
);
694 /* FIXME - what to do here? This case should never happen though, there
695 should always be at least one thread on the system... */
696 /* GspOutBuffer[0] = 'l'; */
699 else if (strncmp(Request
, "sThreadInfo", 11) == 0)
702 PLIST_ENTRY AThread
, AProcess
;
703 PCHAR ptr
= &GspOutBuffer
[1];
705 /* Get next thread id */
706 if (GspEnumThread
!= NULL
)
708 /* find the next thread */
709 Process
= GspEnumThread
->ThreadsProcess
;
710 if (GspEnumThread
->ThreadListEntry
.Flink
!= &Process
->ThreadListHead
)
712 GspEnumThread
= CONTAINING_RECORD(GspEnumThread
->ThreadListEntry
.Flink
,
713 ETHREAD
, ThreadListEntry
);
717 PETHREAD Thread
= NULL
;
718 AProcess
= Process
->ActiveProcessLinks
.Flink
;
719 while (AProcess
!= &PsActiveProcessHead
)
721 Process
= CONTAINING_RECORD(AProcess
, EPROCESS
, ActiveProcessLinks
);
722 AThread
= Process
->ThreadListHead
.Flink
;
723 if (AThread
!= &Process
->ThreadListHead
)
725 Thread
= CONTAINING_RECORD(Process
->ThreadListHead
.Flink
,
726 ETHREAD
, ThreadListEntry
);
729 AProcess
= AProcess
->Flink
;
731 GspEnumThread
= Thread
;
734 if (GspEnumThread
!= NULL
)
737 GspOutBuffer
[0] = 'm';
738 Value
= (ULONG
)GspEnumThread
->Cid
.UniqueThread
;
739 GspLong2Hex(&ptr
, Value
);
743 GspOutBuffer
[0] = 'l';
748 GspOutBuffer
[0] = 'l';
751 else if (strncmp(Request
, "ThreadExtraInfo", 15) == 0)
755 /* Get thread information */
756 if (GspFindThread(Request
+ 16, &ThreadInfo
))
761 Proc
= (PEPROCESS
)ThreadInfo
->ThreadsProcess
;
766 sprintf(Buffer
, "%s [%d:0x%x], ",
768 (int)Proc
->UniqueProcessId
,
769 (int)ThreadInfo
->Cid
.UniqueThread
);
771 strcpy(Buffer
+ strlen(Buffer
), GspThreadStates
[ThreadInfo
->Tcb
.State
]);
773 ObDereferenceObject(ThreadInfo
);
775 GspMem2Hex(Buffer
, &GspOutBuffer
[0], strlen(Buffer
), FALSE
);
778 else if (strncmp(Request
, "Supported", 9) == 0)
780 /* tell maximum incoming packet size */
781 sprintf(GspOutBuffer
, "PacketSize=%u", sizeof(GspInBuffer
) - 1);
783 else if (strncmp(Request
, "Rcmd,", 5) == 0)
789 GspQueryThreadStatus(PCHAR Request
)
792 PCHAR ptr
= &Request
[0];
794 if (GspFindThread(ptr
, &ThreadInfo
))
796 ObDereferenceObject(ThreadInfo
);
798 GspOutBuffer
[0] = 'O';
799 GspOutBuffer
[1] = 'K';
800 GspOutBuffer
[2] = '\0';
804 GspOutBuffer
[0] = 'E';
805 GspOutBuffer
[1] = '\0';
809 #define DR6_BS 0x00004000 /* Single step */
811 #define DR7_L0 0x00000001 /* Local breakpoint 0 enable */
812 #define DR7_G0 0x00000002 /* Global breakpoint 0 enable */
813 #define DR7_L1 0x00000004 /* Local breakpoint 1 enable */
814 #define DR7_G1 0x00000008 /* Global breakpoint 1 enable */
815 #define DR7_L2 0x00000010 /* Local breakpoint 2 enable */
816 #define DR7_G2 0x00000020 /* Global breakpoint 2 enable */
817 #define DR7_L3 0x00000040 /* Local breakpoint 3 enable */
818 #define DR7_G3 0x00000080 /* Global breakpoint 3 enable */
819 #define DR7_LE 0x00000100 /* Local exact breakpoint enable (old) */
820 #define DR7_GE 0x00000200 /* Global exact breakpoint enable (old) */
821 #define DR7_GD 0x00002000 /* General detect enable */
822 #define DR7_TYPE0_MASK 0x00030000 /* Breakpoint 0 condition */
823 #define DR7_LEN0_MASK 0x000c0000 /* Breakpoint 0 length */
824 #define DR7_TYPE1_MASK 0x00300000 /* Breakpoint 1 condition */
825 #define DR7_LEN1_MASK 0x00c00000 /* Breakpoint 1 length */
826 #define DR7_TYPE2_MASK 0x03000000 /* Breakpoint 2 condition */
827 #define DR7_LEN2_MASK 0x0c000000 /* Breakpoint 2 length */
828 #define DR7_TYPE3_MASK 0x30000000 /* Breakpoint 3 condition */
829 #define DR7_LEN3_MASK 0xc0000000 /* Breakpoint 3 length */
830 #define DR7_GLOBAL_ENABLE(Bp) (2 << (2 * (Bp)))
831 #define DR7_TYPE(Bp, Type) ((Type) << (16 + 4 * (Bp)))
832 #define DR7_LEN(Bp, Len) ((Len) << (18 + 4 * (Bp)))
834 #define I386_BP_TYPE_EXECUTE 0
835 #define I386_BP_TYPE_DATA_WRITE 1
836 #define I386_BP_TYPE_DATA_READWRITE 3
838 #define I386_OPCODE_INT3 0xcc
840 #define GDB_ZTYPE_MEMORY_BREAKPOINT 0
841 #define GDB_ZTYPE_HARDWARE_BREAKPOINT 1
842 #define GDB_ZTYPE_WRITE_WATCHPOINT 2
843 #define GDB_ZTYPE_READ_WATCHPOINT 3
844 #define GDB_ZTYPE_ACCESS_WATCHPOINT 4
846 typedef struct _GSPHWBREAKPOINT
853 #define MAX_HW_BREAKPOINTS 4
854 static unsigned GspHwBreakpointCount
= 0;
855 static GSPHWBREAKPOINT GspHwBreakpoints
[MAX_HW_BREAKPOINTS
];
857 typedef struct _GSPSWBREAKPOINT
864 #define MAX_SW_BREAKPOINTS 64
865 static unsigned GspSwBreakpointCount
= 0;
866 static GSPSWBREAKPOINT GspSwBreakpoints
[MAX_SW_BREAKPOINTS
];
869 GspSetHwBreakpoint(ULONG Type
, ULONG_PTR Address
, ULONG Length
)
871 DPRINT("GspSetHwBreakpoint(%lu, 0x%p, %lu)\n", Type
, Address
, Length
);
873 if (GDB_ZTYPE_READ_WATCHPOINT
== Type
)
875 DPRINT1("Read watchpoint not supported\n");
876 strcpy(GspOutBuffer
, "E22");
878 else if (GDB_ZTYPE_HARDWARE_BREAKPOINT
== Type
&& 1 != Length
)
880 DPRINT1("Invalid length %lu for hardware breakpoint\n", Length
);
881 strcpy(GspOutBuffer
, "E22");
883 else if (1 != Length
&& 2 != Length
&& 4 != Length
)
885 DPRINT1("Invalid length %lu for GDB Z type %lu\n", Length
, Type
);
886 strcpy(GspOutBuffer
, "E22");
888 else if (0 != (Address
& (Length
- 1)))
890 DPRINT1("Invalid alignment for address 0x%p and length %d\n", Address
, Length
);
891 strcpy(GspOutBuffer
, "E22");
893 else if (MAX_HW_BREAKPOINTS
== GspHwBreakpointCount
)
895 DPRINT1("Trying to set too many hardware breakpoints\n");
896 strcpy(GspOutBuffer
, "E22");
900 DPRINT("Stored at index %u\n", GspHwBreakpointCount
);
901 GspHwBreakpoints
[GspHwBreakpointCount
].Type
= Type
;
902 GspHwBreakpoints
[GspHwBreakpointCount
].Address
= Address
;
903 GspHwBreakpoints
[GspHwBreakpointCount
].Length
= Length
;
904 GspHwBreakpointCount
++;
905 strcpy(GspOutBuffer
, "OK");
910 GspRemoveHwBreakpoint(ULONG Type
, ULONG_PTR Address
, ULONG Length
)
914 DPRINT("GspRemoveHwBreakpoint(%lu, 0x%p, %lu)\n", Type
, Address
, Length
);
915 for (Index
= 0; Index
< GspHwBreakpointCount
; Index
++)
917 if (GspHwBreakpoints
[Index
].Type
== Type
&&
918 GspHwBreakpoints
[Index
].Address
== Address
&&
919 GspHwBreakpoints
[Index
].Length
== Length
)
921 DPRINT("Found match at index %u\n", Index
);
922 if (Index
+ 1 < GspHwBreakpointCount
)
923 memmove(GspHwBreakpoints
+ Index
,
924 GspHwBreakpoints
+ (Index
+ 1),
925 (GspHwBreakpointCount
- Index
- 1) * sizeof(GSPHWBREAKPOINT
));
927 GspHwBreakpointCount
--;
928 strcpy(GspOutBuffer
, "OK");
933 DPRINT1("Not found\n");
934 strcpy(GspOutBuffer
, "E22");
938 GspFindSwBreakpoint(ULONG_PTR Address
, PULONG PIndex
)
942 for (Index
= 0; Index
< GspSwBreakpointCount
; Index
++)
944 if (GspSwBreakpoints
[Index
].Address
== Address
)
956 GspSetSwBreakpoint(ULONG_PTR Address
)
958 DPRINT("GspSetSwBreakpoint(0x%p)\n", Address
);
960 if (MAX_SW_BREAKPOINTS
== GspSwBreakpointCount
)
962 DPRINT1("Trying to set too many software breakpoints\n");
963 strcpy(GspOutBuffer
, "E22");
967 if (GspFindSwBreakpoint(Address
, NULL
))
969 strcpy(GspOutBuffer
, "E22");
973 DPRINT("Stored at index %u\n", GspSwBreakpointCount
);
974 GspSwBreakpoints
[GspSwBreakpointCount
].Address
= Address
;
975 GspSwBreakpoints
[GspSwBreakpointCount
].Active
= FALSE
;
976 GspSwBreakpointCount
++;
977 strcpy(GspOutBuffer
, "OK");
981 GspRemoveSwBreakpoint(ULONG_PTR Address
)
985 DPRINT("GspRemoveSwBreakpoint(0x%p)\n", Address
);
987 if (GspFindSwBreakpoint(Address
, &Index
))
989 DPRINT("Found match at index %u\n", Index
);
990 ASSERT(!GspSwBreakpoints
[Index
].Active
);
992 if (Index
+ 1 < GspSwBreakpointCount
)
993 memmove(GspSwBreakpoints
+ Index
,
994 GspSwBreakpoints
+ (Index
+ 1),
995 (GspSwBreakpointCount
- Index
- 1) * sizeof(GSPSWBREAKPOINT
));
997 GspSwBreakpointCount
--;
998 strcpy(GspOutBuffer
, "OK");
1002 DPRINT1("Not found\n");
1003 strcpy(GspOutBuffer
, "E22");
1007 GspLoadHwBreakpoint(PKTRAP_FRAME TrapFrame
, unsigned BpIndex
,
1008 ULONG_PTR Address
, ULONG Length
, ULONG Type
)
1010 DPRINT("GspLoadHwBreakpoint(0x%p, %d, 0x%p, %d)\n",
1011 TrapFrame
, BpIndex
, Address
, Type
);
1013 /* Set the DR7_Gx bit to globally enable the breakpoint */
1014 TrapFrame
->Dr7
|= DR7_GLOBAL_ENABLE(BpIndex
) |
1015 DR7_LEN(BpIndex
, Length
) |
1016 DR7_TYPE(BpIndex
, Type
);
1021 DPRINT("Setting DR0 to 0x%p\n", Address
);
1022 TrapFrame
->Dr0
= Address
;
1026 DPRINT("Setting DR1 to 0x%p\n", Address
);
1027 TrapFrame
->Dr1
= Address
;
1031 DPRINT("Setting DR2 to 0x%p\n", Address
);
1032 TrapFrame
->Dr2
= Address
;
1036 DPRINT("Setting DR3 to 0x%p\n", Address
);
1037 TrapFrame
->Dr3
= Address
;
1043 GspLoadSwBreakpoint(ULONG Index
)
1045 GspMemoryError
= FALSE
;
1047 GspSwBreakpoints
[Index
].PrevContent
= GspReadMemSafe((PCHAR
)GspSwBreakpoints
[Index
].Address
);
1049 if (!GspMemoryError
)
1050 GspWriteMemSafe((PCHAR
)GspSwBreakpoints
[Index
].Address
, I386_OPCODE_INT3
);
1052 GspSwBreakpoints
[Index
].Active
= !GspMemoryError
;
1055 DPRINT1("Failed to set software breakpoint at 0x%p\n", GspSwBreakpoints
[Index
].Address
);
1057 DPRINT("Successfully set software breakpoint at 0x%p\n", GspSwBreakpoints
[Index
].Address
);
1061 GspLoadBreakpoints(PKTRAP_FRAME TrapFrame
)
1066 DPRINT("GspLoadBreakpoints\n");
1067 DPRINT("DR7 on entry: 0x%08x\n", TrapFrame
->Dr7
);
1069 /* Remove all breakpoints */
1070 TrapFrame
->Dr7
&= ~(DR7_L0
| DR7_L1
| DR7_L2
| DR7_L3
|
1071 DR7_G0
| DR7_G1
| DR7_G2
| DR7_G3
|
1072 DR7_TYPE0_MASK
| DR7_LEN0_MASK
|
1073 DR7_TYPE1_MASK
| DR7_LEN1_MASK
|
1074 DR7_TYPE2_MASK
| DR7_LEN2_MASK
|
1075 DR7_TYPE3_MASK
| DR7_LEN3_MASK
);
1077 for (Index
= 0; Index
< GspHwBreakpointCount
; Index
++)
1079 switch (GspHwBreakpoints
[Index
].Type
)
1081 case GDB_ZTYPE_HARDWARE_BREAKPOINT
:
1082 i386Type
= I386_BP_TYPE_EXECUTE
;
1084 case GDB_ZTYPE_WRITE_WATCHPOINT
:
1085 i386Type
= I386_BP_TYPE_DATA_WRITE
;
1087 case GDB_ZTYPE_ACCESS_WATCHPOINT
:
1088 i386Type
= I386_BP_TYPE_DATA_READWRITE
;
1092 i386Type
= I386_BP_TYPE_EXECUTE
;
1096 GspLoadHwBreakpoint(TrapFrame
, Index
, GspHwBreakpoints
[Index
].Address
,
1097 GspHwBreakpoints
[Index
].Length
- 1, i386Type
);
1100 for (Index
= 0; Index
< GspSwBreakpointCount
; Index
++)
1102 DPRINT("Using real software breakpoint\n");
1103 GspLoadSwBreakpoint(Index
);
1106 DPRINT("Final DR7 value 0x%08x\n", TrapFrame
->Dr7
);
1110 GspUnloadBreakpoints(void)
1114 DPRINT("GspUnloadBreakpoints\n");
1116 /* Disable hardware debugging while we are inside the stub */
1119 for (Index
= 0; Index
< GspSwBreakpointCount
; Index
++)
1121 if (GspSwBreakpoints
[Index
].Active
)
1123 GspMemoryError
= FALSE
;
1124 GspWriteMemSafe((PCHAR
)GspSwBreakpoints
[Index
].Address
,
1125 GspSwBreakpoints
[Index
].PrevContent
);
1126 GspSwBreakpoints
[Index
].Active
= FALSE
;
1129 DPRINT1("Failed to remove software breakpoint from 0x%p\n",
1130 GspSwBreakpoints
[Index
].Address
);
1134 DPRINT("Successfully removed software breakpoint from 0x%p\n",
1135 GspSwBreakpoints
[Index
].Address
);
1142 GspStopReply(NTSTATUS ExceptionCode
, PKTRAP_FRAME TrapFrame
)
1144 PCHAR ptr
= GspOutBuffer
;
1148 switch (ExceptionCode
)
1150 case STATUS_INTEGER_DIVIDE_BY_ZERO
:
1151 SigVal
= 8; /* divide by zero */
1153 case STATUS_SINGLE_STEP
:
1154 case STATUS_BREAKPOINT
:
1155 SigVal
= 5; /* breakpoint */
1157 case STATUS_INTEGER_OVERFLOW
:
1158 case STATUS_ARRAY_BOUNDS_EXCEEDED
:
1159 SigVal
= 16; /* bound instruction */
1161 case STATUS_ILLEGAL_INSTRUCTION
:
1162 SigVal
= 4; /* Invalid opcode */
1164 case STATUS_STACK_OVERFLOW
:
1165 case STATUS_DATATYPE_MISALIGNMENT
:
1166 case STATUS_ACCESS_VIOLATION
:
1167 SigVal
= 11; /* access violation */
1170 SigVal
= 7; /* "software generated" */
1175 *ptr
++ = 'T'; /* notify gdb with signo, PC, FP and SP */
1176 *ptr
++ = HexChars
[(SigVal
>> 4) & 0xf];
1177 *ptr
++ = HexChars
[SigVal
& 0xf];
1179 *ptr
++ = HexChars
[ESP
];
1182 Esp
= GspGetEspFromTrapFrame(TrapFrame
); /* SP */
1183 ptr
= GspMem2Hex((PCHAR
)&Esp
, ptr
, 4, 0);
1186 *ptr
++ = HexChars
[EBP
];
1188 ptr
= GspMem2Hex((PCHAR
)&TrapFrame
->Ebp
, ptr
, 4, 0); /* FP */
1191 *ptr
++ = HexChars
[PC
];
1193 ptr
= GspMem2Hex((PCHAR
)&TrapFrame
->Eip
, ptr
, 4, 0); /* PC */
1200 * This function does all command procesing for interfacing to GDB.
1204 KdpGdbEnterDebuggerException(PEXCEPTION_RECORD ExceptionRecord
,
1206 PKTRAP_FRAME TrapFrame
)
1208 static BOOLEAN GdbAttached
= FALSE
;
1209 BOOLEAN Stepping
= FALSE
;
1210 NTSTATUS ExceptionCode
;
1215 /* FIXME: Stop on other CPUs too */
1217 DPRINT("Thread %p entering stub\n", PsGetCurrentThread());
1218 ExceptionCode
= (NTSTATUS
)ExceptionRecord
->ExceptionCode
;
1220 /* Can only debug 1 thread at a time... */
1221 ExAcquireFastMutex(&GspLock
);
1222 DPRINT("Thread %p acquired mutex\n", PsGetCurrentThread());
1224 GspUnloadBreakpoints();
1226 /* Make sure we're debugging the current thread. */
1227 if (NULL
!= GspDbgThread
)
1229 DPRINT1("Internal error: entering stub with non-NULL GspDbgThread\n");
1230 ObDereferenceObject(GspDbgThread
);
1231 GspDbgThread
= NULL
;
1236 GspStopReply(ExceptionCode
, TrapFrame
);
1237 GspPutPacket(GspOutBuffer
);
1238 // DbgPrint(">>> (%s) >>>\n", GspOutBuffer);
1247 /* Zero the buffer now so we don't have to worry about the terminating zero character */
1248 memset(GspOutBuffer
, 0, sizeof(GspOutBuffer
));
1249 ptr
= GspGetPacket();
1250 // DbgPrint("<<< (%s) <<<\n", ptr);
1255 /* a little hack to send more complete status information */
1256 GspStopReply(ExceptionCode
, TrapFrame
);
1260 GspRemoteDebug
= !GspRemoteDebug
; /* toggle debug flag */
1263 case 'g': /* return the value of the CPU Registers */
1264 GspGetRegisters(GspOutBuffer
, TrapFrame
);
1267 case 'G': /* set the value of the CPU Registers - return OK */
1268 if (NULL
!= GspDbgThread
)
1269 GspSetRegistersInTrapFrame(ptr
, Context
, GspDbgThread
->Tcb
.TrapFrame
);
1271 GspSetRegistersInTrapFrame(ptr
, Context
, TrapFrame
);
1273 strcpy(GspOutBuffer
, "OK");
1276 case 'P': /* set the value of a single CPU register - return OK */
1280 if ((GspHex2Long(&ptr
, &Register
)) && (*ptr
++ == '='))
1282 if ((Register
>= 0) && (Register
< NUMREGS
))
1286 GspSetSingleRegisterInTrapFrame(ptr
, Register
, Context
,
1287 GspDbgThread
->Tcb
.TrapFrame
);
1291 GspSetSingleRegisterInTrapFrame(ptr
, Register
, Context
, TrapFrame
);
1293 strcpy(GspOutBuffer
, "OK");
1298 strcpy(GspOutBuffer
, "E01");
1302 /* mAA..AA,LLLL Read LLLL bytes at address AA..AA */
1305 /* TRY TO READ %x,%x. IF SUCCEED, SET PTR = 0 */
1306 if (GspHex2Long(&ptr
, &Address
) && *(ptr
++) == ',' && GspHex2Long(&ptr
, &Length
))
1308 PEPROCESS DbgProcess
= NULL
;
1311 if (NULL
!= GspDbgThread
&&
1312 PsGetCurrentProcess() != GspDbgThread
->ThreadsProcess
)
1314 DbgProcess
= GspDbgThread
->ThreadsProcess
;
1315 KeAttachProcess(&DbgProcess
->Pcb
);
1318 GspMemoryError
= FALSE
;
1319 GspMem2Hex((PCHAR
)Address
, GspOutBuffer
, Length
, 1);
1321 if (NULL
!= DbgProcess
)
1326 strcpy(GspOutBuffer
, "E03");
1327 DPRINT1("Fault during memory read\n");
1333 strcpy(GspOutBuffer
, "E01");
1338 /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */
1341 /* TRY TO READ '%x,%x:'. IF SUCCEED, SET PTR = 0 */
1342 if (GspHex2Long(&ptr
, &Address
))
1344 if (*(ptr
++) == ',' && GspHex2Long(&ptr
, &Length
) && *(ptr
++) == ':')
1346 PEPROCESS DbgProcess
= NULL
;
1348 if (NULL
!= GspDbgThread
&&
1349 PsGetCurrentProcess() != GspDbgThread
->ThreadsProcess
)
1351 DbgProcess
= GspDbgThread
->ThreadsProcess
;
1352 KeAttachProcess(&DbgProcess
->Pcb
);
1354 GspMemoryError
= FALSE
;
1355 GspHex2Mem(ptr
, (PCHAR
)Address
, Length
, TRUE
);
1356 if (NULL
!= DbgProcess
)
1361 strcpy(GspOutBuffer
, "E03");
1362 DPRINT1("Fault during memory write\n");
1366 strcpy(GspOutBuffer
, "OK");
1373 strcpy(GspOutBuffer
, "E02");
1378 /* cAA..AA Continue at address AA..AA */
1379 /* sAA..AA Step one instruction from AA..AA */
1384 ULONG BreakpointNumber
;
1387 /* try to read optional parameter, pc changed if param */
1388 if (GspHex2Long(&ptr
, &Address
))
1390 Context
->Eip
= Address
;
1392 else if (ExceptionCode
== STATUS_BREAKPOINT
)
1394 if (GspReadMemSafe((PCHAR
)Context
->Eip
) == (CHAR
)I386_OPCODE_INT3
)
1398 /* clear the trace bit */
1399 Context
->EFlags
&= ~EFLAGS_TF
;
1401 /* set the trace bit if we're Stepping */
1403 Context
->EFlags
|= EFLAGS_TF
;
1406 if (!(Dr6
& DR6_BS
))
1408 for (BreakpointNumber
= 0;
1409 BreakpointNumber
< MAX_HW_BREAKPOINTS
;
1412 if (Dr6
& (1 << BreakpointNumber
))
1414 if (GspHwBreakpoints
[BreakpointNumber
].Type
== I386_BP_TYPE_EXECUTE
)
1416 /* Set restore flag */
1417 Context
->EFlags
|= EFLAGS_RF
;
1424 GspLoadBreakpoints(TrapFrame
);
1427 if (NULL
!= GspDbgThread
)
1429 ObDereferenceObject(GspDbgThread
);
1430 GspDbgThread
= NULL
;
1433 DPRINT("Thread %p releasing mutex\n", PsGetCurrentThread());
1434 ExReleaseFastMutex(&GspLock
);
1435 DPRINT("Thread %p leaving stub\n", PsGetCurrentThread());
1437 if (ExceptionCode
== STATUS_BREAKPOINT
||
1438 ExceptionCode
== STATUS_SINGLE_STEP
)
1441 return kdHandleException
;
1444 case 'k': /* kill the program */
1445 strcpy(GspOutBuffer
, "OK");
1448 case 'H': /* Set thread */
1452 case 'q': /* Query */
1456 case 'T': /* Query thread status */
1457 GspQueryThreadStatus(ptr
);
1466 GspHex2Long(&ptr
, &Type
);
1468 GspHex2Long(&ptr
, &Address
);
1470 GspHex2Long(&ptr
, &Length
);
1473 GspSetSwBreakpoint((ULONG_PTR
)Address
);
1475 GspSetHwBreakpoint(Type
, (ULONG_PTR
)Address
, Length
);
1486 GspHex2Long(&ptr
, &Type
);
1488 GspHex2Long(&ptr
, &Address
);
1490 GspHex2Long(&ptr
, &Length
);
1493 GspRemoveSwBreakpoint((ULONG_PTR
)Address
);
1495 GspRemoveHwBreakpoint(Type
, (ULONG_PTR
)Address
, Length
);
1504 /* reply to the request */
1505 GspPutPacket(GspOutBuffer
);
1506 // DbgPrint(">>> (%s) >>>\n", GspOutBuffer);
1512 GspBreakIn(PKINTERRUPT Interrupt
, PVOID ServiceContext
)
1514 PKTRAP_FRAME TrapFrame
;
1520 DPRINT("Break In\n");
1523 while (KdPortGetByteEx(&GdbPortInfo
, &Value
))
1532 KeRaiseIrql(HIGH_LEVEL
, &OldIrql
);
1534 TrapFrame
= PsGetCurrentThread()->Tcb
.TrapFrame
;
1536 KeTrapFrameToContext(TrapFrame
, NULL
, &Context
);
1538 KdpGdbEnterDebuggerException(NULL
, &Context
, TrapFrame
);
1540 KeContextToTrapFrame(&Context
, NULL
, TrapFrame
, Context
.ContextFlags
, KernelMode
);
1542 KeLowerIrql(OldIrql
);
1549 KdpGdbDebugPrint(PCH Message
, ULONG Length
)
1553 /* Initialize the GDB stub */
1556 KdpGdbStubInit(PKD_DISPATCH_TABLE WrapperTable
, ULONG BootPhase
)
1558 if (!KdDebuggerEnabled
|| !KdpDebugMode
.Gdb
)
1563 ExInitializeFastMutex(&GspLock
);
1565 /* Write out the functions that we support for now */
1566 WrapperTable
->KdpInitRoutine
= KdpGdbStubInit
;
1567 WrapperTable
->KdpPrintRoutine
= KdpGdbDebugPrint
;
1568 WrapperTable
->KdpExceptionRoutine
= KdpGdbEnterDebuggerException
;
1570 /* Initialize the Port */
1571 KdPortInitializeEx(&GdbPortInfo
, GdbPortNumber
);
1573 else if (BootPhase
== 1)
1575 GspInitialized
= TRUE
;
1577 GspRunThread
= NULL
;
1578 GspDbgThread
= NULL
;
1579 GspEnumThread
= NULL
;
1581 HalDisplayString("Waiting for GDB to attach\n");
1582 DbgBreakPointWithStatus(DBG_STATUS_CONTROL_C
);
1584 else if (BootPhase
== 2)
1586 HalDisplayString("\n GDB debugging enabled\n\n");