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 ****************************************************************************/
15 /****************************************************************************
16 * Header: remcom.c,v 1.34 91/03/09 12:29:49 glenne Exp $
18 * Module name: remcom.c $
20 * Date: 91/03/09 12:29:49 $
21 * Contributor: Lake Stevens Instrument Division$
23 * Description: low level support for gdb debugger. $
25 * Considerations: only works on target hardware $
27 * Written by: Glenn Engel $
28 * ModuleState: Experimental $
32 * Modified for 386 by Jim Kingdon, Cygnus Support.
33 * Modified for ReactOS by Casper S. Hornstrup <chorns@users.sourceforge.net>
35 * To enable debugger support, two things need to happen. One, setting
36 * up a routine so that it is in the exception path, is necessary in order
37 * to allow any breakpoints or error conditions to be properly intercepted
38 * and reported to gdb.
39 * Two, a breakpoint needs to be generated to begin communication.
41 * Because gdb will sometimes write to the stack area to execute function
42 * calls, this program cannot rely on using the supervisor stack so it
43 * uses it's own stack area.
47 * The following gdb commands are supported:
49 * command function Return value
51 * g return the value of the CPU Registers hex data or ENN
52 * G set the value of the CPU Registers OK or ENN
54 * mAA..AA,LLLL Read LLLL bytes at address AA..AA hex data or ENN
55 * MAA..AA,LLLL: Write LLLL bytes at address AA.AA OK or ENN
57 * c Resume at current address SNN ( signal NN)
58 * cAA..AA Continue at address AA..AA SNN
60 * s Step one instruction SNN
61 * sAA..AA Step one instruction from AA..AA SNN
65 * ? What was the last sigval ? SNN (signal NN)
67 * All commands and responses are sent with a packet which includes a
68 * Checksum. A packet consists of
70 * $<packet info>#<Checksum>.
73 * <packet info> :: <characters representing the command or response>
74 * <Checksum> :: < two hex digits computed as modulo 256 sum of <packetinfo>>
76 * When a packet is received, it is first acknowledged with either '+' or '-'.
77 * '+' indicates a successful transfer. '-' indicates a failed transfer.
82 * $m0,10#2a +$00010203040506070809101112131415#42
84 ****************************************************************************/
88 #include <internal/debug.h>
89 #include <internal/ps.h>
91 /************************************************************************/
92 /* BUFMAX defines the maximum number of characters in inbound/outbound buffers*/
93 /* at least NUMREGBYTES*2 are needed for register packets */
96 static BOOLEAN GspInitialized
;
98 static PKINTERRUPT GspInterrupt
;
101 static BOOLEAN GspRemoteDebug
;
103 static CONST CHAR HexChars
[]="0123456789abcdef";
105 static PETHREAD GspRunThread
; /* NULL means run all threads */
106 static PETHREAD GspDbgThread
;
107 static PETHREAD GspEnumThread
;
109 extern LIST_ENTRY PsActiveProcessHead
;
110 KD_PORT_INFORMATION GdbPortInfo
= { 2, 115200, 0 }; /* FIXME hardcoded for COM2, 115200 baud */
112 /* Number of Registers. */
117 EAX
, ECX
, EDX
, EBX
, ESP
, EBP
, ESI
, EDI
,
118 PC
/* also known as eip */,
119 PS
/* also known as eflags */,
120 CS
, SS
, DS
, ES
, FS
, GS
123 typedef struct _CPU_REGISTER
127 DWORD OffsetInContext
;
128 BOOLEAN SetInContext
;
129 } CPU_REGISTER
, *PCPU_REGISTER
;
131 #define KTRAP_FRAME_X86 KTRAP_FRAME
138 (*PKSYSTEM_ROUTINE
)(PKSTART_ROUTINE StartRoutine
,
143 KiThreadStartup(PKSYSTEM_ROUTINE SystemRoutine
,
144 PKSTART_ROUTINE StartRoutine
,
147 KTRAP_FRAME TrapFrame
);
149 static CPU_REGISTER GspRegisters
[NUMREGS
] =
151 { 4, FIELD_OFFSET (KTRAP_FRAME_X86
, Eax
), FIELD_OFFSET (CONTEXT
, Eax
), TRUE
},
152 { 4, FIELD_OFFSET (KTRAP_FRAME_X86
, Ecx
), FIELD_OFFSET (CONTEXT
, Ecx
), TRUE
},
153 { 4, FIELD_OFFSET (KTRAP_FRAME_X86
, Edx
), FIELD_OFFSET (CONTEXT
, Edx
), FALSE
},
154 { 4, FIELD_OFFSET (KTRAP_FRAME_X86
, Ebx
), FIELD_OFFSET (CONTEXT
, Ebx
), TRUE
},
155 { 4, FIELD_OFFSET (KTRAP_FRAME_X86
, Esp
), FIELD_OFFSET (CONTEXT
, Esp
), TRUE
},
156 { 4, FIELD_OFFSET (KTRAP_FRAME_X86
, Ebp
), FIELD_OFFSET (CONTEXT
, Ebp
), TRUE
},
157 { 4, FIELD_OFFSET (KTRAP_FRAME_X86
, Esi
), FIELD_OFFSET (CONTEXT
, Esi
), TRUE
},
158 { 4, FIELD_OFFSET (KTRAP_FRAME_X86
, Edi
), FIELD_OFFSET (CONTEXT
, Edi
), TRUE
},
159 { 4, FIELD_OFFSET (KTRAP_FRAME_X86
, Eip
), FIELD_OFFSET (CONTEXT
, Eip
), TRUE
},
160 { 4, FIELD_OFFSET (KTRAP_FRAME_X86
, Eflags
), FIELD_OFFSET (CONTEXT
, EFlags
), TRUE
},
161 { 4, FIELD_OFFSET (KTRAP_FRAME_X86
, Cs
), FIELD_OFFSET (CONTEXT
, SegCs
), TRUE
},
162 { 4, FIELD_OFFSET (KTRAP_FRAME_X86
, Ss
), FIELD_OFFSET (CONTEXT
, SegSs
), TRUE
},
163 { 4, FIELD_OFFSET (KTRAP_FRAME_X86
, Ds
), FIELD_OFFSET (CONTEXT
, SegDs
), TRUE
},
164 { 4, FIELD_OFFSET (KTRAP_FRAME_X86
, Es
), FIELD_OFFSET (CONTEXT
, SegEs
), TRUE
},
165 { 4, FIELD_OFFSET (KTRAP_FRAME_X86
, Fs
), FIELD_OFFSET (CONTEXT
, SegFs
), TRUE
},
166 { 4, FIELD_OFFSET (KTRAP_FRAME_X86
, Gs
), FIELD_OFFSET (CONTEXT
, SegGs
), TRUE
}
169 static PCHAR GspThreadStates
[DeferredReady
+1] =
181 strtok(char *s
, const char *delim
)
189 if (s
== NULL
&& (s
= last
) == NULL
)
193 * Skip (span) leading delimiters (s += strspn(s, delim), sort of).
197 for (spanp
= delim
; (sc
= *spanp
++) != 0;) {
202 if (c
== 0) { /* no non-delimiter characters */
209 * Scan token (scan for delimiters: s += strcspn(s, delim), sort of).
210 * Note that delim must have one NUL; we stop if we see that, too.
216 if ((sc
= *spanp
++) == c
) {
233 if ((ch
>= '0') && (ch
<= '9')) return (ch
- '0');
234 if ((ch
>= 'a') && (ch
<= 'f')) return (ch
- 'a' + 10);
235 if ((ch
>= 'A') && (ch
<= 'F')) return (ch
- 'A' + 10);
239 static CHAR GspInBuffer
[BUFMAX
];
240 static CHAR GspOutBuffer
[BUFMAX
];
243 GdbPutChar(UCHAR Value
)
245 KdPortPutByteEx (&GdbPortInfo
, Value
);
253 while (!KdPortGetByteEx (&GdbPortInfo
, &Value
));
258 /* scan for the sequence $<data>#<Checksum> */
263 PCHAR Buffer
= &GspInBuffer
[0];
271 /* wait around for the start character, ignore all other characters */
272 while ((ch
= GdbGetChar ()) != '$');
279 /* now, read until a # or end of Buffer is found */
280 while (Count
< BUFMAX
)
287 Checksum
= Checksum
+ ch
;
296 XmitChecksum
= (CHAR
)(HexValue (ch
) << 4);
298 XmitChecksum
+= (CHAR
)(HexValue (ch
));
300 if (Checksum
!= XmitChecksum
)
302 GdbPutChar ('-'); /* failed checksum */
306 GdbPutChar ('+'); /* successful transfer */
308 /* if a sequence char is present, reply the sequence ID */
309 if (Buffer
[2] == ':')
311 GdbPutChar (Buffer
[0]);
312 GdbPutChar (Buffer
[1]);
323 /* send the packet in Buffer. */
326 GspPutPacket (PCHAR Buffer
)
332 /* $<packet info>#<Checksum>. */
339 while ((ch
= Buffer
[Count
]))
347 GdbPutChar (HexChars
[(Checksum
>> 4) & 0xf]);
348 GdbPutChar (HexChars
[Checksum
& 0xf]);
350 while (GdbGetChar () != '+');
355 GspPutPacketNoWait (PCHAR Buffer
)
361 /* $<packet info>#<Checksum>. */
366 while ((ch
= Buffer
[Count
]))
374 GdbPutChar (HexChars
[(Checksum
>> 4) & 0xf]);
375 GdbPutChar (HexChars
[Checksum
& 0xf]);
378 /* Indicate to caller of GspMem2Hex or GspHex2Mem that there has been an
380 static volatile BOOLEAN GspMemoryError
= FALSE
;
381 static volatile void *GspAccessLocation
= NULL
;
384 /* Convert the memory pointed to by Address into hex, placing result in Buffer */
385 /* Return a pointer to the last char put in Buffer (null) */
386 /* If MayFault is TRUE, then we should set GspMemoryError in response to
387 a fault; if FALSE treat a fault like any other fault in the stub. */
389 GspMem2Hex (PCHAR Address
,
397 if (NULL
== Address
&& MayFault
)
399 GspMemoryError
= TRUE
;
403 for (i
= 0; i
< (ULONG
) Count
; i
++)
406 GspAccessLocation
= Address
;
408 GspAccessLocation
= NULL
;
409 if (MayFault
&& GspMemoryError
)
413 *Buffer
++ = HexChars
[(ch
>> 4) & 0xf];
414 *Buffer
++ = HexChars
[ch
& 0xf];
422 /* Convert the hex array pointed to by Buffer into binary to be placed at Address */
423 /* Return a pointer to the character AFTER the last byte read from Buffer */
425 GspHex2Mem (PCHAR Buffer
,
438 while ( current
< Address
+ Count
)
440 page
= (PCHAR
)PAGE_ROUND_DOWN (current
);
441 if (Address
+ Count
<= page
+ PAGE_SIZE
)
443 /* Fits in this page */
448 /* Flows into next page, handle only current page in this iteration */
449 countinpage
= PAGE_SIZE
- (Address
- page
);
453 oldprot
= MmGetPageProtect (NULL
, Address
);
454 MmSetPageProtect (NULL
, Address
, PAGE_EXECUTE_READWRITE
);
457 for (i
= 0; i
< countinpage
&& ! GspMemoryError
; i
++)
459 ch
= (CHAR
)(HexValue (*Buffer
++) << 4);
460 ch
= (CHAR
)(ch
+ HexValue (*Buffer
++));
462 GspAccessLocation
= current
;
464 GspAccessLocation
= NULL
;
469 MmSetPageProtect (NULL
, page
, oldprot
);
481 /* This function takes the 386 exception vector and attempts to
482 translate this number into a unix compatible signal value */
484 GspComputeSignal (NTSTATUS ExceptionCode
)
488 switch (ExceptionCode
)
490 case STATUS_INTEGER_DIVIDE_BY_ZERO
:
492 break; /* divide by zero */
493 case STATUS_SINGLE_STEP
:
494 /* debug exception */
495 case STATUS_BREAKPOINT
:
497 break; /* breakpoint */
498 case STATUS_INTEGER_OVERFLOW
:
499 /* into instruction (overflow) */
500 case STATUS_ARRAY_BOUNDS_EXCEEDED
:
502 break; /* bound instruction */
503 case STATUS_ILLEGAL_INSTRUCTION
:
505 break; /* Invalid opcode */
507 case STATUS_FLT_INVALID_OPERATION
:
509 break; /* coprocessor not available */
511 case STATUS_STACK_OVERFLOW
:
512 /* stack exception */
513 case STATUS_DATATYPE_MISALIGNMENT
:
515 case STATUS_ACCESS_VIOLATION
:
516 SigVal
= 11; /* access violation */
519 SigVal
= 7; /* "software generated" */
525 /**********************************************/
526 /* WHILE WE FIND NICE HEX CHARS, BUILD A LONG */
527 /* RETURN NUMBER OF CHARS PROCESSED */
528 /**********************************************/
530 GspHex2Long (PCHAR
*Address
,
540 Hex
= HexValue (**Address
);
543 *Value
= (*Value
<< 4) | Hex
;
557 GspLong2Hex (PCHAR
*Address
,
562 Save
= (((Value
>> 0) & 0xff) << 24) |
563 (((Value
>> 8) & 0xff) << 16) |
564 (((Value
>> 16) & 0xff) << 8) |
565 (((Value
>> 24) & 0xff) << 0);
566 *Address
= GspMem2Hex ((PCHAR
) &Save
, *Address
, 4, FALSE
);
571 * When coming from kernel mode, Esp is not stored in the trap frame.
572 * Instead, it was pointing to the location of the TrapFrame Esp member
573 * when the exception occured. When coming from user mode, Esp is just
574 * stored in the TrapFrame Esp member.
577 GspGetEspFromTrapFrame(PKTRAP_FRAME TrapFrame
)
580 return KeGetPreviousMode() == KernelMode
581 ? (LONG
) &TrapFrame
->Esp
: TrapFrame
->Esp
;
586 GspGetRegistersFromTrapFrame(PCHAR Address
,
588 PKTRAP_FRAME TrapFrame
)
596 for (i
= 0; i
< sizeof (GspRegisters
) / sizeof (GspRegisters
[0]); i
++)
602 Value
= GspGetEspFromTrapFrame (TrapFrame
);
606 p
= (PULONG
) ((ULONG_PTR
) TrapFrame
+ GspRegisters
[i
].OffsetInTF
);
610 else if (i
== EIP_REGNO
)
613 * This thread has not been sheduled yet so assume it
614 * is still in PsBeginThreadWithContextInternal().
616 Value
= (ULONG
)KiThreadStartup
;
622 Buffer
= GspMem2Hex ((PCHAR
) &Value
, Buffer
, GspRegisters
[i
].Size
, FALSE
);
628 GspSetRegistersInTrapFrame(PCHAR Address
,
630 PKTRAP_FRAME TrapFrame
)
641 for (i
= 0; i
< NUMREGS
; i
++)
643 if (GspRegisters
[i
].SetInContext
)
644 p
= (PULONG
) ((ULONG_PTR
) Context
+ GspRegisters
[i
].OffsetInContext
);
646 p
= (PULONG
) ((ULONG_PTR
) TrapFrame
+ GspRegisters
[i
].OffsetInTF
);
648 Buffer
= GspHex2Mem (Buffer
, (PCHAR
) &Value
, GspRegisters
[i
].Size
, FALSE
);
655 GspSetSingleRegisterInTrapFrame(PCHAR Address
,
658 PKTRAP_FRAME TrapFrame
)
666 if (GspRegisters
[Number
].SetInContext
)
667 p
= (PULONG
) ((ULONG_PTR
) Context
+ GspRegisters
[Number
].OffsetInContext
);
669 p
= (PULONG
) ((ULONG_PTR
) TrapFrame
+ GspRegisters
[Number
].OffsetInTF
);
671 GspHex2Mem (Address
, (PCHAR
) &Value
, GspRegisters
[Number
].Size
, FALSE
);
677 GspFindThread(PCHAR Data
,
680 PETHREAD ThreadInfo
= NULL
;
682 if (strcmp (Data
, "-1") == 0)
691 PCHAR ptr
= &Data
[0];
693 GspHex2Long (&ptr
, (PULONG
) &uThreadId
);
694 ThreadId
= (HANDLE
)uThreadId
;
696 if (!NT_SUCCESS (PsLookupThreadByThreadId (ThreadId
, &ThreadInfo
)))
702 *Thread
= ThreadInfo
;
708 GspSetThread(PCHAR Request
)
711 PCHAR ptr
= &Request
[1];
715 case 'c': /* Run thread */
716 if (GspFindThread (ptr
, &ThreadInfo
))
718 GspOutBuffer
[0] = 'O';
719 GspOutBuffer
[1] = 'K';
721 if (NULL
!= GspRunThread
)
723 ObDereferenceObject(GspRunThread
);
725 GspRunThread
= ThreadInfo
;
726 if (NULL
!= GspRunThread
)
728 ObReferenceObject(GspRunThread
);
733 GspOutBuffer
[0] = 'E';
736 case 'g': /* Debug thread */
737 if (GspFindThread (ptr
, &ThreadInfo
))
739 GspOutBuffer
[0] = 'O';
740 GspOutBuffer
[1] = 'K';
742 if(GspDbgThread
) ObDereferenceObject(GspDbgThread
);
744 GspDbgThread
= ThreadInfo
;
748 GspOutBuffer
[0] = 'E';
758 GspQuery(PCHAR Request
)
763 Command
= strtok (Request
, ",");
764 if (strncmp (Command
, "C", 1) == 0)
766 PCHAR ptr
= &GspOutBuffer
[2];
768 /* Get current thread id */
769 GspOutBuffer
[0] = 'Q';
770 GspOutBuffer
[1] = 'C';
771 if (NULL
!= GspDbgThread
)
773 Value
= (ULONG
) GspDbgThread
->Cid
.UniqueThread
;
777 Value
= (ULONG
) PsGetCurrentThread()->Cid
.UniqueThread
;
779 GspLong2Hex (&ptr
, Value
);
781 else if (strncmp (Command
, "fThreadInfo", 11) == 0)
784 PLIST_ENTRY AThread
, AProcess
;
785 PCHAR ptr
= &GspOutBuffer
[1];
787 /* Get first thread id */
788 GspEnumThread
= NULL
;
789 AProcess
= PsActiveProcessHead
.Flink
;
790 while(AProcess
!= &PsActiveProcessHead
)
792 Process
= CONTAINING_RECORD(AProcess
, EPROCESS
, ActiveProcessLinks
);
793 AThread
= Process
->ThreadListHead
.Flink
;
794 if(AThread
!= &Process
->ThreadListHead
)
796 GspEnumThread
= CONTAINING_RECORD (Process
->ThreadListHead
.Flink
,
797 ETHREAD
, ThreadListEntry
);
800 AProcess
= AProcess
->Flink
;
802 if(GspEnumThread
!= NULL
)
804 GspOutBuffer
[0] = 'm';
805 Value
= (ULONG
) GspEnumThread
->Cid
.UniqueThread
;
806 GspLong2Hex (&ptr
, Value
);
810 /* FIXME - what to do here? This case should never happen though, there
811 should always be at least one thread on the system... */
812 /* GspOutBuffer[0] = 'l'; */
815 else if (strncmp (Command
, "sThreadInfo", 11) == 0)
818 PLIST_ENTRY AThread
, AProcess
;
819 PCHAR ptr
= &GspOutBuffer
[1];
821 /* Get next thread id */
822 if (GspEnumThread
!= NULL
)
824 /* find the next thread */
825 Process
= GspEnumThread
->ThreadsProcess
;
826 if(GspEnumThread
->ThreadListEntry
.Flink
!= &Process
->ThreadListHead
)
828 GspEnumThread
= CONTAINING_RECORD (GspEnumThread
->ThreadListEntry
.Flink
,
829 ETHREAD
, ThreadListEntry
);
833 PETHREAD Thread
= NULL
;
834 AProcess
= Process
->ActiveProcessLinks
.Flink
;
835 while(AProcess
!= &PsActiveProcessHead
)
837 Process
= CONTAINING_RECORD(AProcess
, EPROCESS
, ActiveProcessLinks
);
838 AThread
= Process
->ThreadListHead
.Flink
;
839 if(AThread
!= &Process
->ThreadListHead
)
841 Thread
= CONTAINING_RECORD (Process
->ThreadListHead
.Flink
,
842 ETHREAD
, ThreadListEntry
);
845 AProcess
= AProcess
->Flink
;
847 GspEnumThread
= Thread
;
850 if(GspEnumThread
!= NULL
)
853 GspOutBuffer
[0] = 'm';
854 Value
= (ULONG
) GspEnumThread
->Cid
.UniqueThread
;
855 GspLong2Hex (&ptr
, Value
);
859 GspOutBuffer
[0] = 'l';
864 GspOutBuffer
[0] = 'l';
867 else if (strncmp (Command
, "ThreadExtraInfo", 15) == 0)
870 PCHAR ptr
= &Command
[15];
872 /* Get thread information */
873 if (GspFindThread (ptr
, &ThreadInfo
))
875 PCHAR String
= GspThreadStates
[ThreadInfo
->Tcb
.State
];
877 ObDereferenceObject(ThreadInfo
);
879 GspMem2Hex (String
, &GspOutBuffer
[0], strlen (String
), FALSE
);
883 else if (strncmp (Command
, "L", 1) == 0)
885 PLIST_ENTRY CurrentEntry
;
887 ULONG MaxThreads
= 0;
889 ULONG ThreadCount
= 0;
892 GspHex2Mem (&Request
[1], (PCHAR
) &MaxThreads
, 2, TRUE
);
893 GspHex2Mem (&Request
[3], (PCHAR
) &Value
, 4, TRUE
);
894 GspHex2Mem (&Request
[11], (PCHAR
) &ThreadId
, 4, TRUE
);
896 GspOutBuffer
[0] = 'q';
897 GspOutBuffer
[1] = 'M';
899 GspMem2Hex ((PCHAR
) &Value
, &GspOutBuffer
[5], 4, TRUE
);
900 GspMem2Hex ((PCHAR
) &ThreadId
, &GspOutBuffer
[13], 4, TRUE
);
902 CurrentEntry
= PiThreadListHead
.Flink
;
903 while ((CurrentEntry
!= &PiThreadListHead
) && (ThreadCount
< MaxThreads
))
905 Current
= CONTAINING_RECORD (CurrentEntry
, ETHREAD
, Tcb
.ThreadListEntry
);
907 GspMem2Hex ((PCHAR
) &Value
, &GspOutBuffer
[21+ThreadCount
*16], 4, TRUE
);
908 Value
= (ULONG
) Current
->Cid
.UniqueThread
;
909 GspMem2Hex ((PCHAR
) &Value
, &GspOutBuffer
[21+ThreadCount
*16+8], 4, TRUE
);
910 CurrentEntry
= CurrentEntry
->Flink
;
914 if (CurrentEntry
!= &PiThreadListHead
)
916 GspOutBuffer
[4] = '0';
920 GspOutBuffer
[4] = '1';
923 GspMem2Hex ((PCHAR
) &ThreadCount
, &GspOutBuffer
[2], 1, TRUE
);
926 else if (strncmp (Command
, "Offsets", 7) == 0)
928 strcpy (GspOutBuffer
, "Text=0;Data=0;Bss=0");
933 GspQueryThreadStatus(PCHAR Request
)
936 PCHAR ptr
= &Request
[0];
938 if (GspFindThread (ptr
, &ThreadInfo
))
940 ObDereferenceObject(ThreadInfo
);
942 GspOutBuffer
[0] = 'O';
943 GspOutBuffer
[1] = 'K';
944 GspOutBuffer
[2] = '\0';
948 GspOutBuffer
[0] = 'E';
949 GspOutBuffer
[1] = '\0';
954 typedef struct _GsHwBreakPoint
962 #if defined(__GNUC__)
963 GsHwBreakPoint GspBreakpoints
[4] =
971 GsHwBreakPoint GspBreakpoints
[4] =
981 GspCorrectHwBreakpoint()
983 ULONG BreakpointNumber
;
988 #if defined(__GNUC__)
990 "movl %%db7, %0\n" : "=r" (dr7_
) : );
993 ULONG addr0
, addr1
, addr2
, addr3
;
1000 : "=r" (addr0
), "=r" (addr1
),
1001 "=r" (addr2
), "=r" (addr3
) : );
1003 #elif defined(_MSC_VER)
1006 mov eax
, dr7
; mov dr7_
, eax
;
1007 mov eax
, dr0
; mov addr0
, eax
;
1008 mov eax
, dr1
; mov addr1
, eax
;
1009 mov eax
, dr2
; mov addr2
, eax
;
1010 mov eax
, dr3
; mov addr3
, eax
;
1013 #error Unknown compiler for inline assembler
1016 for (BreakpointNumber
= 0; BreakpointNumber
< 3; BreakpointNumber
++)
1018 Bit
= 2 << (BreakpointNumber
<< 1);
1019 if (!(dr7_
& Bit
) && GspBreakpoints
[BreakpointNumber
].Enabled
) {
1022 dr7_
&= ~(0xf0000 << (BreakpointNumber
<< 2));
1023 dr7_
|= (((GspBreakpoints
[BreakpointNumber
].Length
<< 2) |
1024 GspBreakpoints
[BreakpointNumber
].Type
) << 16) << (BreakpointNumber
<< 2);
1025 switch (BreakpointNumber
) {
1026 #if defined(__GNUC__)
1028 asm volatile ("movl %0, %%dr0\n"
1029 : : "r" (GspBreakpoints
[BreakpointNumber
].Address
) );
1033 asm volatile ("movl %0, %%dr1\n"
1034 : : "r" (GspBreakpoints
[BreakpointNumber
].Address
) );
1038 asm volatile ("movl %0, %%dr2\n"
1039 : : "r" (GspBreakpoints
[BreakpointNumber
].Address
) );
1043 asm volatile ("movl %0, %%dr3\n"
1044 : : "r" (GspBreakpoints
[BreakpointNumber
].Address
) );
1046 #elif defined(_MSC_VER)
1049 ULONG addr
= GspBreakpoints
[BreakpointNumber
].Address
;
1050 __asm mov eax
, addr
;
1056 ULONG addr
= GspBreakpoints
[BreakpointNumber
].Address
;
1057 __asm mov eax
, addr
;
1063 ULONG addr
= GspBreakpoints
[BreakpointNumber
].Address
;
1064 __asm mov eax
, addr
;
1070 ULONG addr
= GspBreakpoints
[BreakpointNumber
].Address
;
1071 __asm mov eax
, addr
;
1076 #error Unknown compiler for inline assembler
1080 else if ((dr7_
& Bit
) && !GspBreakpoints
[BreakpointNumber
].Enabled
)
1084 dr7_
&= ~(0xf0000 << (BreakpointNumber
<< 2));
1089 #if defined(__GNUC__)
1090 asm volatile ( "movl %0, %%db7\n" : : "r" (dr7_
));
1091 #elif defined(_MSC_VER)
1092 __asm mov eax
, dr7_
;
1095 #error Unknown compiler for inline assembler
1101 GspRemoveHwBreakpoint(ULONG BreakpointNumber
)
1103 if (!GspBreakpoints
[BreakpointNumber
].Enabled
)
1107 GspBreakpoints
[BreakpointNumber
].Enabled
= 0;
1113 GspSetHwBreakpoint(ULONG BreakpointNumber
,
1118 if (GspBreakpoints
[BreakpointNumber
].Enabled
)
1122 GspBreakpoints
[BreakpointNumber
].Enabled
= TRUE
;
1123 GspBreakpoints
[BreakpointNumber
].Type
= Type
;
1124 GspBreakpoints
[BreakpointNumber
].Length
= Length
;
1125 GspBreakpoints
[BreakpointNumber
].Address
= Address
;
1131 * This function does all command procesing for interfacing to gdb.
1135 KdpGdbEnterDebuggerException(PEXCEPTION_RECORD ExceptionRecord
,
1137 PKTRAP_FRAME TrapFrame
)
1147 /* FIXME: Stop on other CPUs too */
1148 /* Disable hardware debugging while we are inside the stub */
1149 #if defined(__GNUC__)
1150 __asm__("movl %0,%%db7" : /* no output */ : "r" (0));
1151 #elif defined(_MSC_VER)
1152 __asm mov eax
, 0 __asm mov dr7
, eax
1154 #error Unknown compiler for inline assembler
1157 if (STATUS_ACCESS_VIOLATION
== (NTSTATUS
) ExceptionRecord
->ExceptionCode
&&
1158 NULL
!= GspAccessLocation
&&
1159 (ULONG_PTR
) GspAccessLocation
==
1160 (ULONG_PTR
) ExceptionRecord
->ExceptionInformation
[1])
1162 GspAccessLocation
= NULL
;
1163 GspMemoryError
= TRUE
;
1164 TrapFrame
->Eip
+= 2;
1168 /* Don't switch threads */
1170 /* Always use the current thread when entering the exception handler */
1171 if (NULL
!= GspDbgThread
)
1173 ObDereferenceObject(GspDbgThread
);
1174 GspDbgThread
= NULL
;
1177 /* reply to host that an exception has occurred */
1178 SigVal
= GspComputeSignal (ExceptionRecord
->ExceptionCode
);
1180 ptr
= &GspOutBuffer
[0];
1182 *ptr
++ = 'T'; /* notify gdb with signo, PC, FP and SP */
1183 *ptr
++ = HexChars
[(SigVal
>> 4) & 0xf];
1184 *ptr
++ = HexChars
[SigVal
& 0xf];
1186 *ptr
++ = HexChars
[ESP
];
1189 Esp
= GspGetEspFromTrapFrame (TrapFrame
); /* SP */
1190 ptr
= GspMem2Hex ((PCHAR
) &Esp
, ptr
, 4, 0);
1193 *ptr
++ = HexChars
[EBP
];
1195 ptr
= GspMem2Hex ((PCHAR
) &TrapFrame
->Ebp
, ptr
, 4, 0); /* FP */
1198 *ptr
++ = HexChars
[PC
];
1200 ptr
= GspMem2Hex((PCHAR
) &TrapFrame
->Eip
, ptr
, 4, 0); /* PC */
1205 GspPutPacket (&GspOutBuffer
[0]);
1211 /* Zero the buffer now so we don't have to worry about the terminating zero character */
1212 memset (GspOutBuffer
, 0, sizeof (GspInBuffer
));
1213 ptr
= GspGetPacket ();
1218 GspOutBuffer
[0] = 'S';
1219 GspOutBuffer
[1] = HexChars
[SigVal
>> 4];
1220 GspOutBuffer
[2] = HexChars
[SigVal
% 16];
1221 GspOutBuffer
[3] = 0;
1224 GspRemoteDebug
= !GspRemoteDebug
; /* toggle debug flag */
1226 case 'g': /* return the value of the CPU Registers */
1227 if (NULL
!= GspDbgThread
)
1229 GspGetRegistersFromTrapFrame (&GspOutBuffer
[0], Context
, GspDbgThread
->Tcb
.TrapFrame
);
1233 GspGetRegistersFromTrapFrame (&GspOutBuffer
[0], Context
, TrapFrame
);
1236 case 'G': /* set the value of the CPU Registers - return OK */
1237 if (NULL
!= GspDbgThread
)
1239 GspSetRegistersInTrapFrame (ptr
, Context
, GspDbgThread
->Tcb
.TrapFrame
);
1243 GspSetRegistersInTrapFrame (ptr
, Context
, TrapFrame
);
1245 strcpy (GspOutBuffer
, "OK");
1247 case 'P': /* set the value of a single CPU register - return OK */
1251 if ((GspHex2Long (&ptr
, &Register
)) && (*ptr
++ == '='))
1252 if ((Register
>= 0) && (Register
< NUMREGS
))
1256 GspSetSingleRegisterInTrapFrame(ptr
, Register
,
1257 Context
, GspDbgThread
->Tcb
.TrapFrame
);
1261 GspSetSingleRegisterInTrapFrame (ptr
, Register
, Context
, TrapFrame
);
1263 strcpy (GspOutBuffer
, "OK");
1267 strcpy (GspOutBuffer
, "E01");
1271 /* mAA..AA,LLLL Read LLLL bytes at address AA..AA */
1273 /* TRY TO READ %x,%x. IF SUCCEED, SET PTR = 0 */
1274 if (GspHex2Long (&ptr
, &Address
))
1275 if (*(ptr
++) == ',')
1276 if (GspHex2Long (&ptr
, &Length
))
1279 GspMemoryError
= FALSE
;
1280 GspMem2Hex ((PCHAR
) Address
, GspOutBuffer
, Length
, 1);
1283 strcpy (GspOutBuffer
, "E03");
1284 DPRINT ("Fault during memory read\n");
1289 strcpy (GspOutBuffer
, "E01");
1292 /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */
1294 /* TRY TO READ '%x,%x:'. IF SUCCEED, SET PTR = 0 */
1295 if (GspHex2Long (&ptr
, &Address
))
1296 if (*(ptr
++) == ',')
1297 if (GspHex2Long (&ptr
, &Length
))
1298 if (*(ptr
++) == ':')
1300 GspMemoryError
= FALSE
;
1301 GspHex2Mem (ptr
, (PCHAR
) Address
, Length
, TRUE
);
1305 strcpy (GspOutBuffer
, "E03");
1306 DPRINT ("Fault during memory write\n");
1310 strcpy (GspOutBuffer
, "OK");
1316 strcpy (GspOutBuffer
, "E02");
1319 /* cAA..AA Continue at address AA..AA(optional) */
1320 /* sAA..AA Step one instruction from AA..AA(optional) */
1325 ULONG BreakpointNumber
;
1328 /* try to read optional parameter, pc unchanged if no parm */
1329 if (GspHex2Long (&ptr
, &Address
))
1330 Context
->Eip
= Address
;
1332 NewPC
= Context
->Eip
;
1334 /* clear the trace bit */
1335 Context
->EFlags
&= 0xfffffeff;
1337 /* set the trace bit if we're Stepping */
1339 Context
->EFlags
|= 0x100;
1341 #if defined(__GNUC__)
1342 asm volatile ("movl %%db6, %0\n" : "=r" (dr6_
) : );
1343 #elif defined(_MSC_VER)
1344 __asm mov eax
, dr6 __asm mov dr6_
, eax
;
1346 #error Unknown compiler for inline assembler
1348 if (!(dr6_
& 0x4000))
1350 for (BreakpointNumber
= 0; BreakpointNumber
< 4; ++BreakpointNumber
)
1352 if (dr6_
& (1 << BreakpointNumber
))
1354 if (GspBreakpoints
[BreakpointNumber
].Type
== 0)
1356 /* Set restore flag */
1357 Context
->EFlags
|= 0x10000;
1363 GspCorrectHwBreakpoint();
1364 #if defined(__GNUC__)
1365 asm volatile ("movl %0, %%db6\n" : : "r" (0));
1366 #elif defined(_MSC_VER)
1367 __asm mov eax
, 0 __asm mov dr6
, eax
;
1369 #error Unknown compiler for inline assembler
1372 KeContextToTrapFrame(Context
, TrapFrame
);
1373 return ((SigVal
== 5) ? (kdContinue
) : (kdHandleException
));
1377 case 'k': /* kill the program */
1378 strcpy (GspOutBuffer
, "OK");
1380 /* kill the program */
1382 case 'H': /* Set thread */
1386 case 'q': /* Query */
1390 case 'T': /* Query thread status */
1391 GspQueryThreadStatus (ptr
);
1401 ptr
= &GspOutBuffer
[1];
1402 GspHex2Long (&ptr
, &Number
);
1404 GspHex2Long (&ptr
, &Type
);
1406 GspHex2Long (&ptr
, &Length
);
1408 GspHex2Long (&ptr
, &Address
);
1409 if (GspSetHwBreakpoint (Number
& 0x3, Type
& 0x3 , Length
& 0x3, Address
) == 0)
1411 strcpy (GspOutBuffer
, "OK");
1415 strcpy (GspOutBuffer
, "E");
1420 /* Remove hardware breakpoint */
1425 ptr
= &GspOutBuffer
[1];
1426 GspHex2Long(&ptr
, &Number
);
1427 if (GspRemoveHwBreakpoint (Number
& 0x3) == 0)
1429 strcpy (GspOutBuffer
, "OK");
1433 strcpy (GspOutBuffer
, "E");
1442 /* reply to the request */
1443 GspPutPacket (&GspOutBuffer
[0]);
1450 return kdDoNotHandleException
;
1456 GspBreakIn(PKINTERRUPT Interrupt
,
1457 PVOID ServiceContext
)
1459 PKTRAP_FRAME TrapFrame
;
1465 DPRINT ("Break In\n");
1468 while (KdPortGetByteEx (&GdbPortInfo
, &Value
))
1477 KeRaiseIrql (HIGH_LEVEL
, &OldIrql
);
1479 TrapFrame
= PsGetCurrentThread()->Tcb
.TrapFrame
;
1481 KeTrapFrameToContext (TrapFrame
, &Context
);
1483 KdpGdbEnterDebuggerException (NULL
, &Context
, TrapFrame
);
1485 KeContextToTrapFrame (&Context
, TrapFrame
);
1487 KeLowerIrql (OldIrql
);
1493 extern ULONG KdpPortIrq
;
1498 KdpGdbDebugPrint(PCH Message
)
1501 /* This can be quite annoying! */
1506 GspOutBuffer
[0] = 'O';
1507 GspOutBuffer
[1] = '\0';
1508 strcat (&GspOutBuffer
[0], Message
);
1509 Length
= strlen (Message
);
1510 GspOutBuffer
[2 + Length
] = '\n';
1511 GspOutBuffer
[3 + Length
] = '\0';
1512 GspPutPacketNoWait (&GspOutBuffer
[0]);
1518 extern LIST_ENTRY ModuleListHead
;
1523 PLIST_ENTRY CurrentEntry
;
1524 PMODULE_OBJECT Current
;
1531 CurrentEntry
= ModuleListHead
.Flink
;
1532 while (CurrentEntry
!= (&ModuleListHead
))
1534 Current
= CONTAINING_RECORD (CurrentEntry
, MODULE_OBJECT
, ListEntry
);
1536 DbgPrint ("Module %S Base 0x%.08x Length 0x%.08x\n",
1537 Current
->BaseName
.Buffer
, Current
->Base
, Current
->Length
);
1540 CurrentEntry
= CurrentEntry
->Flink
;
1543 DbgPrint ("%d modules listed\n", ModuleCount
);
1546 /* Initialize the GDB stub */
1549 KdpGdbStubInit(PKD_DISPATCH_TABLE WrapperTable
,
1552 if (!KdDebuggerEnabled
|| !KdpDebugMode
.Gdb
) return;
1556 /* Write out the functions that we support for now */
1557 WrapperTable
->KdpInitRoutine
= KdpGdbStubInit
;
1558 WrapperTable
->KdpPrintRoutine
= KdpGdbDebugPrint
;
1559 WrapperTable
->KdpExceptionRoutine
= KdpGdbEnterDebuggerException
;
1561 /* Initialize the Port */
1562 KdPortInitializeEx(&GdbPortInfo
, 0, 0);
1564 else if (BootPhase
== 1)
1566 GspInitialized
= TRUE
;
1568 GspRunThread
= NULL
;
1569 GspDbgThread
= NULL
;
1570 GspEnumThread
= NULL
;
1572 HalDisplayString("Waiting for GDB to attach\n");
1573 DbgPrint("Module 'hal.dll' loaded at 0x%.08x.\n", LdrHalBase
);
1574 DbgBreakPointWithStatus (DBG_STATUS_CONTROL_C
);
1576 else if (BootPhase
== 2)
1578 HalDisplayString("\n GDB debugging enabled\n\n");