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 ****************************************************************************/
87 #include <internal/kd.h>
88 #include <internal/ke.h>
89 #include <internal/ps.h>
92 #include <internal/debug.h>
94 extern LIST_ENTRY PiThreadListHead
;
97 /************************************************************************/
98 /* BUFMAX defines the maximum number of characters in inbound/outbound buffers*/
99 /* at least NUMREGBYTES*2 are needed for register packets */
102 static BOOLEAN GspInitialized
; /* boolean flag. TRUE means we've been initialized */
103 static PKINTERRUPT GspInterrupt
;
105 static BOOLEAN GspRemoteDebug
;
107 static CONST CHAR HexChars
[]="0123456789abcdef";
109 static PETHREAD GspRunThread
; /* NULL means run all threads */
110 static PETHREAD GspDbgThread
;
111 static PETHREAD GspEnumThread
;
113 /* Number of Registers. */
118 EAX
, ECX
, EDX
, EBX
, ESP
, EBP
, ESI
, EDI
,
119 PC
/* also known as eip */,
120 PS
/* also known as eflags */,
121 CS
, SS
, DS
, ES
, FS
, GS
124 typedef struct _CPU_REGISTER
128 } CPU_REGISTER
, *PCPU_REGISTER
;
130 #define KTRAP_FRAME_X86 KTRAP_FRAME
134 static CPU_REGISTER GspRegisters
[NUMREGS
] =
136 { 4, FIELD_OFFSET (KTRAP_FRAME_X86
, Eax
) },
137 { 4, FIELD_OFFSET (KTRAP_FRAME_X86
, Ecx
) },
138 { 4, FIELD_OFFSET (KTRAP_FRAME_X86
, Edx
) },
139 { 4, FIELD_OFFSET (KTRAP_FRAME_X86
, Ebx
) },
140 { 4, FIELD_OFFSET (KTRAP_FRAME_X86
, Esp
) },
141 { 4, FIELD_OFFSET (KTRAP_FRAME_X86
, Ebp
) },
142 { 4, FIELD_OFFSET (KTRAP_FRAME_X86
, Esi
) },
143 { 4, FIELD_OFFSET (KTRAP_FRAME_X86
, Edi
) },
144 { 4, FIELD_OFFSET (KTRAP_FRAME_X86
, Eip
) },
145 { 4, FIELD_OFFSET (KTRAP_FRAME_X86
, Eflags
) },
146 { 4, FIELD_OFFSET (KTRAP_FRAME_X86
, Cs
) },
147 { 4, FIELD_OFFSET (KTRAP_FRAME_X86
, Ss
) },
148 { 4, FIELD_OFFSET (KTRAP_FRAME_X86
, Ds
) },
149 { 4, FIELD_OFFSET (KTRAP_FRAME_X86
, Es
) },
150 { 4, FIELD_OFFSET (KTRAP_FRAME_X86
, Fs
) },
151 { 4, FIELD_OFFSET (KTRAP_FRAME_X86
, Gs
) }
154 static CHAR GspThreadStates
[THREAD_STATE_MAX
] =
156 "Invalid", /* THREAD_STATE_INVALID */
157 "Runnable", /* THREAD_STATE_RUNNABLE */
158 "Running", /* THREAD_STATE_RUNNING */
159 "Suspended", /* THREAD_STATE_SUSPENDED */
160 "Frozen", /* THREAD_STATE_FROZEN */
161 "Terminated 1", /* THREAD_STATE_TERMINATED_1 */
162 "Terminated 2", /* THREAD_STATE_TERMINATED_2 */
163 "Blocked" /* THREAD_STATE_BLOCKED */
167 strtok(char *s
, const char *delim
)
175 if (s
== NULL
&& (s
= last
) == NULL
)
179 * Skip (span) leading delimiters (s += strspn(s, delim), sort of).
183 for (spanp
= delim
; (sc
= *spanp
++) != 0;) {
188 if (c
== 0) { /* no non-delimiter characters */
195 * Scan token (scan for delimiters: s += strcspn(s, delim), sort of).
196 * Note that delim must have one NUL; we stop if we see that, too.
202 if ((sc
= *spanp
++) == c
) {
219 if ((ch
>= '0') && (ch
<= '9')) return (ch
- '0');
220 if ((ch
>= 'a') && (ch
<= 'f')) return (ch
- 'a' + 10);
221 if ((ch
>= 'A') && (ch
<= 'F')) return (ch
- 'A' + 10);
225 static CHAR GspInBuffer
[BUFMAX
];
226 static CHAR GspOutBuffer
[BUFMAX
];
228 /* scan for the sequence $<data>#<Checksum> */
233 PCHAR Buffer
= &GspInBuffer
[0];
241 /* wait around for the start character, ignore all other characters */
242 while ((ch
= KdGetChar ()) != '$');
249 /* now, read until a # or end of Buffer is found */
250 while (Count
< BUFMAX
)
257 Checksum
= Checksum
+ ch
;
266 XmitChecksum
= HexValue (ch
) << 4;
268 XmitChecksum
+= HexValue (ch
);
270 if (Checksum
!= XmitChecksum
)
272 KdPutChar ('-'); /* failed checksum */
276 KdPutChar ('+'); /* successful transfer */
278 /* if a sequence char is present, reply the sequence ID */
279 if (Buffer
[2] == ':')
281 KdPutChar (Buffer
[0]);
282 KdPutChar (Buffer
[1]);
293 /* send the packet in Buffer. */
296 GspPutPacket (PCHAR Buffer
)
302 /* $<packet info>#<Checksum>. */
309 while ((ch
= Buffer
[Count
]))
317 KdPutChar (HexChars
[(Checksum
>> 4) & 0xf]);
318 KdPutChar (HexChars
[Checksum
& 0xf]);
320 while (KdGetChar () != '+');
325 GspPutPacketNoWait (PCHAR Buffer
)
331 /* $<packet info>#<Checksum>. */
336 while ((ch
= Buffer
[Count
]))
344 KdPutChar (HexChars
[(Checksum
>> 4) & 0xf]);
345 KdPutChar (HexChars
[Checksum
& 0xf]);
350 GspDebugError(LPSTR Message
)
352 DbgPrint ("%s\n", Message
);
355 /* Address of a routine to RTE to if we get a memory fault. */
356 static VOID (*volatile MemoryFaultRoutine
) () = NULL
;
358 /* Indicate to caller of GspMem2Hex or GspHex2Mem that there has been an
360 static volatile BOOLEAN GspMemoryError
= FALSE
;
363 /* Currently not used */
367 GspMemoryError
= TRUE
;
371 /* These are separate functions so that they are so short and sweet
372 that the compiler won't save any Registers (if there is a fault
373 to MemoryFaultRoutine, they won't get restored, so there better
374 not be any saved). */
376 GspGetChar (PCHAR Address
)
383 GspSetChar (PCHAR Address
,
390 /* Convert the memory pointed to by Address into hex, placing result in Buffer */
391 /* Return a pointer to the last char put in Buffer (null) */
392 /* If MayFault is TRUE, then we should set GspMemoryError in response to
393 a fault; if FALSE treat a fault like any other fault in the stub. */
395 GspMem2Hex (PCHAR Address
,
404 MemoryFaultRoutine
= GspSetMemoryError
;
405 for (i
= 0; i
< Count
; i
++)
407 ch
= GspGetChar (Address
++);
408 if (MayFault
&& GspMemoryError
)
410 *Buffer
++ = HexChars
[(ch
>> 4) & 0xf];
411 *Buffer
++ = HexChars
[ch
& 0xf];
415 MemoryFaultRoutine
= NULL
;
420 /* Convert the hex array pointed to by Buffer into binary to be placed at Address */
421 /* Return a pointer to the character AFTER the last byte read from Buffer */
423 GspHex2Mem (PCHAR Buffer
,
432 MemoryFaultRoutine
= GspSetMemoryError
;
433 for (i
= 0; i
< Count
; i
++)
435 ch
= HexValue (*Buffer
++) << 4;
436 ch
= ch
+ HexValue (*Buffer
++);
437 GspSetChar (Address
++, ch
);
438 if (MayFault
&& GspMemoryError
)
442 MemoryFaultRoutine
= NULL
;
447 /* This function takes the 386 exception vector and attempts to
448 translate this number into a unix compatible signal value */
450 GspComputeSignal (NTSTATUS ExceptionCode
)
454 switch (ExceptionCode
)
456 case STATUS_INTEGER_DIVIDE_BY_ZERO
:
458 break; /* divide by zero */
459 case STATUS_SINGLE_STEP
:
461 break; /* debug exception */
462 case STATUS_BREAKPOINT
:
464 break; /* breakpoint */
465 case STATUS_INTEGER_OVERFLOW
:
467 break; /* into instruction (overflow) */
468 case STATUS_ARRAY_BOUNDS_EXCEEDED
:
470 break; /* bound instruction */
471 case STATUS_ILLEGAL_INSTRUCTION
:
473 break; /* Invalid opcode */
475 case STATUS_FLT_INVALID_OPERATION
:
477 break; /* coprocessor not available */
479 case STATUS_STACK_OVERFLOW
:
481 break; /* stack exception */
482 case STATUS_DATATYPE_MISALIGNMENT
:
484 break; /* page fault */
486 SigVal
= 7; /* "software generated" */
492 /**********************************************/
493 /* WHILE WE FIND NICE HEX CHARS, BUILD A LONG */
494 /* RETURN NUMBER OF CHARS PROCESSED */
495 /**********************************************/
497 GspHex2Long (PCHAR
*Address
,
507 Hex
= HexValue (**Address
);
510 *Value
= (*Value
<< 4) | Hex
;
524 GspLong2Hex (PCHAR
*Address
,
529 Save
= (((Value
>> 0) & 0xf) << 24) |
530 (((Value
>> 8) & 0xf) << 16) |
531 (((Value
>> 16) & 0xf) << 8) |
532 (((Value
>> 24) & 0xf) << 0);
533 *Address
= GspMem2Hex ((PCHAR
) &Save
, *Address
, 4, FALSE
);
538 GspGetRegistersFromTrapFrame(PCHAR Address
,
539 PKTRAP_FRAME TrapFrame
)
548 Regs
= &GspRegisters
[0];
549 for (i
= 0; i
< NUMREGS
; i
++)
553 p
= (PULONG
) ((ULONG_PTR
) TrapFrame
+ Regs
[i
].OffsetInTF
);
556 else if (i
== EIP_REGNO
)
559 * This thread has not been sheduled yet so assume it
560 * is still in PsBeginThreadWithContextInternal().
562 Value
= (ULONG
) PsBeginThreadWithContextInternal
;
568 Buffer
= GspMem2Hex ((PCHAR
) &Value
, Buffer
, Regs
[i
].Size
, FALSE
);
574 GspSetRegistersInTrapFrame(PCHAR Address
,
575 PKTRAP_FRAME TrapFrame
)
587 Regs
= &GspRegisters
[0];
588 for (i
= 0; i
< NUMREGS
; i
++)
590 p
= (PULONG
) ((ULONG_PTR
) TrapFrame
+ Regs
[i
].OffsetInTF
);
592 Buffer
= GspHex2Mem (Buffer
, (PCHAR
) &Value
, Regs
[i
].Size
, FALSE
);
599 GspSetSingleRegisterInTrapFrame(PCHAR Address
,
601 PKTRAP_FRAME TrapFrame
)
609 p
= (PULONG
) ((ULONG_PTR
) TrapFrame
+ GspRegisters
[Number
].OffsetInTF
);
611 GspHex2Mem (Address
, (PCHAR
) &Value
, GspRegisters
[Number
].Size
, FALSE
);
617 GspFindThread(PCHAR Data
,
620 PETHREAD ThreadInfo
= NULL
;
622 if (strcmp (Data
, "-1") == 0)
627 else if (strcmp (Data
, "0") == 0)
629 /* Pick any thread, pick the first thread,
630 * which is what most people are interested in
632 ThreadInfo
= CONTAINING_RECORD (PiThreadListHead
.Flink
,
633 ETHREAD
, Tcb
.ThreadListEntry
);
638 PCHAR ptr
= &Data
[0];
640 GspHex2Long (&ptr
, (PLONG
) &ThreadId
);
642 if (!NT_SUCCESS (PsLookupThreadByThreadId ((PVOID
) ThreadId
, &ThreadInfo
)))
648 *Thread
= ThreadInfo
;
654 GspSetThread(PCHAR Request
)
657 PCHAR ptr
= &Request
[1];
661 case 'c': /* Run thread */
662 if (GspFindThread (ptr
, &ThreadInfo
))
664 GspOutBuffer
[0] = 'O';
665 GspOutBuffer
[1] = 'K';
666 GspRunThread
= ThreadInfo
;
670 GspOutBuffer
[0] = 'E';
673 case 'g': /* Debug thread */
674 if (GspFindThread (ptr
, &ThreadInfo
))
676 GspOutBuffer
[0] = 'O';
677 GspOutBuffer
[1] = 'K';
678 GspDbgThread
= ThreadInfo
;
682 GspOutBuffer
[0] = 'E';
692 GspQuery(PCHAR Request
)
697 Command
= strtok (Request
, ",");
698 if (strncmp (Command
, "C", 1) == 0)
700 PCHAR ptr
= &GspOutBuffer
[2];
702 /* Get current thread id */
703 GspOutBuffer
[0] = 'Q';
704 GspOutBuffer
[1] = 'C';
705 Value
= (ULONG
) GspDbgThread
->Cid
.UniqueThread
;
706 GspLong2Hex (&ptr
, Value
);
708 else if (strncmp (Command
, "fThreadInfo", 11) == 0)
710 PCHAR ptr
= &GspOutBuffer
[1];
712 /* Get first thread id */
713 GspOutBuffer
[0] = 'm';
714 GspEnumThread
= CONTAINING_RECORD (PiThreadListHead
.Flink
,
715 ETHREAD
, Tcb
.ThreadListEntry
);
716 Value
= (ULONG
) GspEnumThread
->Cid
.UniqueThread
;
717 GspLong2Hex (&ptr
, Value
);
719 else if (strncmp (Command
, "sThreadInfo", 11) == 0)
721 PCHAR ptr
= &GspOutBuffer
[1];
723 /* Get next thread id */
724 if ((GspEnumThread
) && (GspEnumThread
->Tcb
.ThreadListEntry
.Flink
!= PiThreadListHead
.Flink
))
726 GspEnumThread
= CONTAINING_RECORD (GspEnumThread
->Tcb
.ThreadListEntry
.Flink
,
727 ETHREAD
, Tcb
.ThreadListEntry
);
728 GspOutBuffer
[0] = 'm';
729 Value
= (ULONG
) GspEnumThread
->Cid
.UniqueThread
;
730 GspLong2Hex (&ptr
, Value
);
734 GspOutBuffer
[0] = '1';
737 else if (strncmp (Command
, "ThreadExtraInfo", 15) == 0)
740 PCHAR ptr
= &Command
[15];
742 /* Get thread information */
743 if (GspFindThread (ptr
, &ThreadInfo
))
745 PCHAR String
= &GspThreadStates
[ThreadInfo
->Tcb
.State
];
746 GspMem2Hex (String
, &GspOutBuffer
[0], strlen (String
), FALSE
);
750 else if (strncmp (Command
, "L", 1) == 0)
752 PLIST_ENTRY CurrentEntry
;
754 ULONG MaxThreads
= 0;
756 ULONG ThreadCount
= 0;
759 GspHex2Mem (&Request
[1], (PCHAR
) &MaxThreads
, 2, TRUE
);
760 GspHex2Mem (&Request
[3], (PCHAR
) &Value
, 4, TRUE
);
761 GspHex2Mem (&Request
[11], (PCHAR
) &ThreadId
, 4, TRUE
);
763 GspOutBuffer
[0] = 'q';
764 GspOutBuffer
[1] = 'M';
766 GspMem2Hex ((PCHAR
) &Value
, &GspOutBuffer
[5], 4, TRUE
);
767 GspMem2Hex ((PCHAR
) &ThreadId
, &GspOutBuffer
[13], 4, TRUE
);
769 CurrentEntry
= PiThreadListHead
.Flink
;
770 while ((CurrentEntry
!= &PiThreadListHead
) && (ThreadCount
< MaxThreads
))
772 Current
= CONTAINING_RECORD (CurrentEntry
, ETHREAD
, Tcb
.ThreadListEntry
);
774 GspMem2Hex ((PCHAR
) &Value
, &GspOutBuffer
[21+ThreadCount
*16], 4, TRUE
);
775 Value
= (ULONG
) Current
->Cid
.UniqueThread
;
776 GspMem2Hex ((PCHAR
) &Value
, &GspOutBuffer
[21+ThreadCount
*16+8], 4, TRUE
);
777 CurrentEntry
= CurrentEntry
->Flink
;
781 if (CurrentEntry
!= &PiThreadListHead
)
783 GspOutBuffer
[4] = '0';
787 GspOutBuffer
[4] = '1';
790 GspMem2Hex ((PCHAR
) &ThreadCount
, &GspOutBuffer
[2], 1, TRUE
);
793 else if (strncmp (Command
, "Offsets", 7) == 0)
795 strcpy (GspOutBuffer
, "Text=0;Data=0;Bss=0");
800 GspQueryThreadStatus(PCHAR Request
)
803 PCHAR ptr
= &Request
[0];
805 if (GspFindThread (ptr
, &ThreadInfo
))
807 GspOutBuffer
[0] = 'O';
808 GspOutBuffer
[1] = 'K';
809 GspOutBuffer
[2] = '\0';
813 GspOutBuffer
[0] = 'E';
814 GspOutBuffer
[1] = '\0';
819 typedef struct _GsHwBreakPoint
827 GsHwBreakPoint GspBreakpoints
[4] =
836 GspCorrectHwBreakpoint()
838 ULONG BreakpointNumber
;
844 "movl %%db7, %0\n" : "=r" (dr7
) : );
847 ULONG addr0
, addr1
, addr2
, addr3
;
854 : "=r" (addr0
), "=r" (addr1
),
855 "=r" (addr2
), "=r" (addr3
) : );
858 for (BreakpointNumber
= 0; BreakpointNumber
< 3; BreakpointNumber
++)
860 Bit
= 2 << (BreakpointNumber
<< 1);
861 if (!(dr7
& Bit
) && GspBreakpoints
[BreakpointNumber
].Enabled
) {
864 dr7
&= ~(0xf0000 << (BreakpointNumber
<< 2));
865 dr7
|= (((GspBreakpoints
[BreakpointNumber
].Length
<< 2) |
866 GspBreakpoints
[BreakpointNumber
].Type
) << 16) << (BreakpointNumber
<< 2);
867 switch (BreakpointNumber
) {
869 asm volatile ("movl %0, %%dr0\n"
870 : : "r" (GspBreakpoints
[BreakpointNumber
].Address
) );
874 asm volatile ("movl %0, %%dr1\n"
875 : : "r" (GspBreakpoints
[BreakpointNumber
].Address
) );
879 asm volatile ("movl %0, %%dr2\n"
880 : : "r" (GspBreakpoints
[BreakpointNumber
].Address
) );
884 asm volatile ("movl %0, %%dr3\n"
885 : : "r" (GspBreakpoints
[BreakpointNumber
].Address
) );
889 else if ((dr7
& Bit
) && !GspBreakpoints
[BreakpointNumber
].Enabled
)
893 dr7
&= ~(0xf0000 << (BreakpointNumber
<< 2));
898 asm volatile ( "movl %0, %%db7\n" : : "r" (dr7
));
903 GspRemoveHwBreakpoint(ULONG BreakpointNumber
)
905 if (!GspBreakpoints
[BreakpointNumber
].Enabled
)
909 GspBreakpoints
[BreakpointNumber
].Enabled
= 0;
915 GspSetHwBreakpoint(ULONG BreakpointNumber
,
920 if (GspBreakpoints
[BreakpointNumber
].Enabled
)
924 GspBreakpoints
[BreakpointNumber
].Enabled
= TRUE
;
925 GspBreakpoints
[BreakpointNumber
].Type
= Type
;
926 GspBreakpoints
[BreakpointNumber
].Length
= Length
;
927 GspBreakpoints
[BreakpointNumber
].Address
= Address
;
933 * This function does all command procesing for interfacing to gdb.
936 KdEnterDebuggerException(PEXCEPTION_RECORD ExceptionRecord
,
938 PKTRAP_FRAME TrapFrame
)
947 /* FIXME: Stop on other CPUs too */
948 /* Disable hardware debugging while we are inside the stub */
949 __asm__("movl %0,%%db7" : /* no output */ : "r" (0));
951 /* reply to host that an exception has occurred */
952 SigVal
= GspComputeSignal (ExceptionRecord
->ExceptionCode
);
954 ptr
= &GspOutBuffer
[0];
956 *ptr
++ = 'T'; /* notify gdb with signo, PC, FP and SP */
957 *ptr
++ = HexChars
[(SigVal
>> 4) & 0xf];
958 *ptr
++ = HexChars
[SigVal
& 0xf];
960 *ptr
++ = HexChars
[ESP
];
962 ptr
= GspMem2Hex ((PCHAR
) &TrapFrame
->Esp
, ptr
, 4, 0); /* SP */
965 *ptr
++ = HexChars
[EBP
];
967 ptr
= GspMem2Hex ((PCHAR
) &TrapFrame
->Ebp
, ptr
, 4, 0); /* FP */
970 *ptr
++ = HexChars
[PC
];
972 ptr
= GspMem2Hex((PCHAR
) &TrapFrame
->Eip
, ptr
, 4, 0); /* PC */
977 GspPutPacket (&GspOutBuffer
[0]);
983 /* Zero the buffer now so we don't have to worry about the terminating zero character */
984 memset (GspOutBuffer
, 0, sizeof (GspInBuffer
));
985 ptr
= GspGetPacket ();
990 GspOutBuffer
[0] = 'S';
991 GspOutBuffer
[1] = HexChars
[SigVal
>> 4];
992 GspOutBuffer
[2] = HexChars
[SigVal
% 16];
996 GspRemoteDebug
= !GspRemoteDebug
; /* toggle debug flag */
998 case 'g': /* return the value of the CPU Registers */
1000 GspGetRegistersFromTrapFrame (&GspOutBuffer
[0], GspDbgThread
->Tcb
.TrapFrame
);
1002 GspGetRegistersFromTrapFrame (&GspOutBuffer
[0], TrapFrame
);
1004 case 'G': /* set the value of the CPU Registers - return OK */
1006 GspSetRegistersInTrapFrame (ptr
, GspDbgThread
->Tcb
.TrapFrame
);
1008 GspSetRegistersInTrapFrame (ptr
, TrapFrame
);
1009 strcpy (GspOutBuffer
, "OK");
1011 case 'P': /* set the value of a single CPU register - return OK */
1015 if ((GspHex2Long (&ptr
, &Register
)) && (*ptr
++ == '='))
1016 if ((Register
>= 0) && (Register
< NUMREGS
))
1019 GspSetSingleRegisterInTrapFrame (ptr
, Register
,
1020 GspDbgThread
->Tcb
.TrapFrame
);
1022 GspSetSingleRegisterInTrapFrame (ptr
, Register
, TrapFrame
);
1023 strcpy (GspOutBuffer
, "OK");
1027 strcpy (GspOutBuffer
, "E01");
1031 /* mAA..AA,LLLL Read LLLL bytes at address AA..AA */
1033 /* TRY TO READ %x,%x. IF SUCCEED, SET PTR = 0 */
1034 if (GspHex2Long (&ptr
, &Address
))
1035 if (*(ptr
++) == ',')
1036 if (GspHex2Long (&ptr
, &Length
))
1039 GspMemoryError
= FALSE
;
1040 GspMem2Hex ((PCHAR
) Address
, GspOutBuffer
, Length
, 1);
1043 strcpy (GspOutBuffer
, "E03");
1044 GspDebugError ("memory fault");
1050 strcpy (GspOutBuffer
, "E01");
1054 /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */
1056 /* TRY TO READ '%x,%x:'. IF SUCCEED, SET PTR = 0 */
1057 if (GspHex2Long (&ptr
, &Address
))
1058 if (*(ptr
++) == ',')
1059 if (GspHex2Long (&ptr
, &Length
))
1060 if (*(ptr
++) == ':')
1062 GspMemoryError
= FALSE
;
1063 GspHex2Mem (ptr
, (PCHAR
) Address
, Length
, TRUE
);
1067 strcpy (GspOutBuffer
, "E03");
1068 GspDebugError ("memory fault");
1072 strcpy (GspOutBuffer
, "OK");
1079 strcpy (GspOutBuffer
, "E02");
1083 /* cAA..AA Continue at address AA..AA(optional) */
1084 /* sAA..AA Step one instruction from AA..AA(optional) */
1089 ULONG BreakpointNumber
;
1092 /* try to read optional parameter, pc unchanged if no parm */
1093 if (GspHex2Long (&ptr
, &Address
))
1094 Context
->Eip
= Address
;
1096 NewPC
= Context
->Eip
;
1098 /* clear the trace bit */
1099 Context
->EFlags
&= 0xfffffeff;
1101 /* set the trace bit if we're Stepping */
1103 Context
->EFlags
|= 0x100;
1105 asm volatile ("movl %%db6, %0\n" : "=r" (dr6
) : );
1106 if (!(dr6
& 0x4000))
1108 for (BreakpointNumber
= 0; BreakpointNumber
< 4; ++BreakpointNumber
)
1110 if (dr6
& (1 << BreakpointNumber
))
1112 if (GspBreakpoints
[BreakpointNumber
].Type
== 0)
1114 /* Set restore flag */
1115 Context
->EFlags
|= 0x10000;
1121 GspCorrectHwBreakpoint();
1122 asm volatile ("movl %0, %%db6\n" : : "r" (0));
1124 return kdHandleException
;
1127 case 'k': /* kill the program */
1128 strcpy (GspOutBuffer
, "OK");
1130 /* kill the program */
1131 case 'H': /* Set thread */
1134 case 'q': /* Query */
1137 case 'T': /* Query thread status */
1138 GspQueryThreadStatus (ptr
);
1147 ptr
= &GspOutBuffer
[1];
1148 GspHex2Long (&ptr
, &Number
);
1150 GspHex2Long (&ptr
, &Type
);
1152 GspHex2Long (&ptr
, &Length
);
1154 GspHex2Long (&ptr
, &Address
);
1155 if (GspSetHwBreakpoint (Number
& 0x3, Type
& 0x3 , Length
& 0x3, Address
) == 0)
1157 strcpy (GspOutBuffer
, "OK");
1161 strcpy (GspOutBuffer
, "E");
1164 /* Remove hardware breakpoint */
1170 ptr
= &GspOutBuffer
[1];
1171 GspHex2Long(&ptr
, &Number
);
1172 if (GspRemoveHwBreakpoint (Number
& 0x3) == 0)
1174 strcpy (GspOutBuffer
, "OK");
1178 strcpy (GspOutBuffer
, "E");
1186 /* reply to the request */
1187 GspPutPacket (&GspOutBuffer
[0]);
1190 return kdDoNotHandleException
;
1196 GspBreakIn(PKINTERRUPT Interrupt
,
1197 PVOID ServiceContext
)
1199 PKTRAP_FRAME TrapFrame
;
1205 DPRINT ("Break In\n");
1208 while (KdPortGetByte (&Value
))
1217 KeRaiseIrql (HIGH_LEVEL
, &OldIrql
);
1219 TrapFrame
= PsGetCurrentThread()->Tcb
.TrapFrame
;
1221 KeTrapFrameToContext (TrapFrame
, &Context
);
1223 KdEnterDebuggerException (NULL
, &Context
, TrapFrame
);
1225 KeContextToTrapFrame (&Context
, TrapFrame
);
1227 KeLowerIrql (OldIrql
);
1233 extern ULONG KdpPortIrq
;
1235 /* Initialize the GDB stub */
1237 KdGdbStubInit(ULONG Phase
)
1246 GspInitialized
= TRUE
;
1247 GspRunThread
= PsGetCurrentThread();
1248 GspDbgThread
= PsGetCurrentThread();
1249 GspEnumThread
= NULL
;
1251 else if (Phase
== 1)
1253 /* Hook an interrupt handler to allow the debugger to break into
1255 MappedIrq
= HalGetInterruptVector (Internal
,
1262 Status
= IoConnectInterrupt(&GspInterrupt
,
1273 if (!NT_SUCCESS (Status
))
1275 DPRINT1("Could not connect to IRQ line %d (0x%x)\n",
1276 KdpPortIrq
, Status
);
1280 KdPortEnableInterrupts();
1282 DbgBreakPointWithStatus (DBG_STATUS_CONTROL_C
);
1286 /* This function will generate a breakpoint exception. It is used at the
1287 beginning of a program to sync up with a debugger and can be used
1288 otherwise as a quick means to stop program execution and "break" into
1292 KdGdbDebugPrint (LPSTR Message
)
1294 /* This can be quite annoying! */
1300 GspOutBuffer
[0] = 'O';
1301 GspOutBuffer
[1] = '\0';
1302 strcat (&GspOutBuffer
[0], Message
);
1303 Length
= strlen (Message
);
1304 GspOutBuffer
[2 + Length
] = '\n';
1305 GspOutBuffer
[3 + Length
] = '\0';
1306 GspPutPacketNoWait (&GspOutBuffer
[0]);