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>
90 #include <internal/ldr.h>
93 #include <internal/debug.h>
95 extern LIST_ENTRY PiThreadListHead
;
98 /************************************************************************/
99 /* BUFMAX defines the maximum number of characters in inbound/outbound buffers*/
100 /* at least NUMREGBYTES*2 are needed for register packets */
103 static BOOLEAN GspInitialized
; /* boolean flag. TRUE means we've been initialized */
104 static PKINTERRUPT GspInterrupt
;
106 static BOOLEAN GspRemoteDebug
;
108 static CONST CHAR HexChars
[]="0123456789abcdef";
110 static PETHREAD GspRunThread
; /* NULL means run all threads */
111 static PETHREAD GspDbgThread
;
112 static PETHREAD GspEnumThread
;
114 /* Number of Registers. */
119 EAX
, ECX
, EDX
, EBX
, ESP
, EBP
, ESI
, EDI
,
120 PC
/* also known as eip */,
121 PS
/* also known as eflags */,
122 CS
, SS
, DS
, ES
, FS
, GS
125 typedef struct _CPU_REGISTER
129 } CPU_REGISTER
, *PCPU_REGISTER
;
131 #define KTRAP_FRAME_X86 KTRAP_FRAME
135 static CPU_REGISTER GspRegisters
[NUMREGS
] =
137 { 4, FIELD_OFFSET (KTRAP_FRAME_X86
, Eax
) },
138 { 4, FIELD_OFFSET (KTRAP_FRAME_X86
, Ecx
) },
139 { 4, FIELD_OFFSET (KTRAP_FRAME_X86
, Edx
) },
140 { 4, FIELD_OFFSET (KTRAP_FRAME_X86
, Ebx
) },
141 { 4, FIELD_OFFSET (KTRAP_FRAME_X86
, Esp
) },
142 { 4, FIELD_OFFSET (KTRAP_FRAME_X86
, Ebp
) },
143 { 4, FIELD_OFFSET (KTRAP_FRAME_X86
, Esi
) },
144 { 4, FIELD_OFFSET (KTRAP_FRAME_X86
, Edi
) },
145 { 4, FIELD_OFFSET (KTRAP_FRAME_X86
, Eip
) },
146 { 4, FIELD_OFFSET (KTRAP_FRAME_X86
, Eflags
) },
147 { 4, FIELD_OFFSET (KTRAP_FRAME_X86
, Cs
) },
148 { 4, FIELD_OFFSET (KTRAP_FRAME_X86
, Ss
) },
149 { 4, FIELD_OFFSET (KTRAP_FRAME_X86
, Ds
) },
150 { 4, FIELD_OFFSET (KTRAP_FRAME_X86
, Es
) },
151 { 4, FIELD_OFFSET (KTRAP_FRAME_X86
, Fs
) },
152 { 4, FIELD_OFFSET (KTRAP_FRAME_X86
, Gs
) }
155 static PCHAR GspThreadStates
[THREAD_STATE_MAX
] =
157 "Invalid", /* THREAD_STATE_INVALID */
158 "Runnable", /* THREAD_STATE_RUNNABLE */
159 "Running", /* THREAD_STATE_RUNNING */
160 "Suspended", /* THREAD_STATE_SUSPENDED */
161 "Frozen", /* THREAD_STATE_FROZEN */
162 "Terminated 1", /* THREAD_STATE_TERMINATED_1 */
163 "Terminated 2", /* THREAD_STATE_TERMINATED_2 */
164 "Blocked" /* THREAD_STATE_BLOCKED */
168 strtok(char *s
, const char *delim
)
176 if (s
== NULL
&& (s
= last
) == NULL
)
180 * Skip (span) leading delimiters (s += strspn(s, delim), sort of).
184 for (spanp
= delim
; (sc
= *spanp
++) != 0;) {
189 if (c
== 0) { /* no non-delimiter characters */
196 * Scan token (scan for delimiters: s += strcspn(s, delim), sort of).
197 * Note that delim must have one NUL; we stop if we see that, too.
203 if ((sc
= *spanp
++) == c
) {
220 if ((ch
>= '0') && (ch
<= '9')) return (ch
- '0');
221 if ((ch
>= 'a') && (ch
<= 'f')) return (ch
- 'a' + 10);
222 if ((ch
>= 'A') && (ch
<= 'F')) return (ch
- 'A' + 10);
226 static CHAR GspInBuffer
[BUFMAX
];
227 static CHAR GspOutBuffer
[BUFMAX
];
229 /* scan for the sequence $<data>#<Checksum> */
234 PCHAR Buffer
= &GspInBuffer
[0];
242 /* wait around for the start character, ignore all other characters */
243 while ((ch
= KdGetChar ()) != '$');
250 /* now, read until a # or end of Buffer is found */
251 while (Count
< BUFMAX
)
258 Checksum
= Checksum
+ ch
;
267 XmitChecksum
= HexValue (ch
) << 4;
269 XmitChecksum
+= HexValue (ch
);
271 if (Checksum
!= XmitChecksum
)
273 KdPutChar ('-'); /* failed checksum */
277 KdPutChar ('+'); /* successful transfer */
279 /* if a sequence char is present, reply the sequence ID */
280 if (Buffer
[2] == ':')
282 KdPutChar (Buffer
[0]);
283 KdPutChar (Buffer
[1]);
294 /* send the packet in Buffer. */
297 GspPutPacket (PCHAR Buffer
)
303 /* $<packet info>#<Checksum>. */
310 while ((ch
= Buffer
[Count
]))
318 KdPutChar (HexChars
[(Checksum
>> 4) & 0xf]);
319 KdPutChar (HexChars
[Checksum
& 0xf]);
321 while (KdGetChar () != '+');
326 GspPutPacketNoWait (PCHAR Buffer
)
332 /* $<packet info>#<Checksum>. */
337 while ((ch
= Buffer
[Count
]))
345 KdPutChar (HexChars
[(Checksum
>> 4) & 0xf]);
346 KdPutChar (HexChars
[Checksum
& 0xf]);
351 GspDebugError(LPSTR Message
)
353 DbgPrint ("%s\n", Message
);
356 /* Address of a routine to RTE to if we get a memory fault. */
357 static VOID (*volatile MemoryFaultRoutine
) () = NULL
;
359 /* Indicate to caller of GspMem2Hex or GspHex2Mem that there has been an
361 static volatile BOOLEAN GspMemoryError
= FALSE
;
364 /* Currently not used */
368 GspMemoryError
= TRUE
;
372 /* These are separate functions so that they are so short and sweet
373 that the compiler won't save any Registers (if there is a fault
374 to MemoryFaultRoutine, they won't get restored, so there better
375 not be any saved). */
377 GspGetChar (PCHAR Address
)
384 GspSetChar (PCHAR Address
,
391 /* Convert the memory pointed to by Address into hex, placing result in Buffer */
392 /* Return a pointer to the last char put in Buffer (null) */
393 /* If MayFault is TRUE, then we should set GspMemoryError in response to
394 a fault; if FALSE treat a fault like any other fault in the stub. */
396 GspMem2Hex (PCHAR Address
,
405 MemoryFaultRoutine
= GspSetMemoryError
;
406 for (i
= 0; i
< Count
; i
++)
408 ch
= GspGetChar (Address
++);
409 if (MayFault
&& GspMemoryError
)
411 *Buffer
++ = HexChars
[(ch
>> 4) & 0xf];
412 *Buffer
++ = HexChars
[ch
& 0xf];
416 MemoryFaultRoutine
= NULL
;
421 /* Convert the hex array pointed to by Buffer into binary to be placed at Address */
422 /* Return a pointer to the character AFTER the last byte read from Buffer */
424 GspHex2Mem (PCHAR Buffer
,
433 MemoryFaultRoutine
= GspSetMemoryError
;
434 for (i
= 0; i
< Count
; i
++)
436 ch
= HexValue (*Buffer
++) << 4;
437 ch
= ch
+ HexValue (*Buffer
++);
438 GspSetChar (Address
++, ch
);
439 if (MayFault
&& GspMemoryError
)
443 MemoryFaultRoutine
= NULL
;
448 /* This function takes the 386 exception vector and attempts to
449 translate this number into a unix compatible signal value */
451 GspComputeSignal (NTSTATUS ExceptionCode
)
455 switch (ExceptionCode
)
457 case STATUS_INTEGER_DIVIDE_BY_ZERO
:
459 break; /* divide by zero */
460 case STATUS_SINGLE_STEP
:
462 break; /* debug exception */
463 case STATUS_BREAKPOINT
:
465 break; /* breakpoint */
466 case STATUS_INTEGER_OVERFLOW
:
468 break; /* into instruction (overflow) */
469 case STATUS_ARRAY_BOUNDS_EXCEEDED
:
471 break; /* bound instruction */
472 case STATUS_ILLEGAL_INSTRUCTION
:
474 break; /* Invalid opcode */
476 case STATUS_FLT_INVALID_OPERATION
:
478 break; /* coprocessor not available */
480 case STATUS_STACK_OVERFLOW
:
482 break; /* stack exception */
483 case STATUS_DATATYPE_MISALIGNMENT
:
485 break; /* page fault */
487 SigVal
= 7; /* "software generated" */
493 /**********************************************/
494 /* WHILE WE FIND NICE HEX CHARS, BUILD A LONG */
495 /* RETURN NUMBER OF CHARS PROCESSED */
496 /**********************************************/
498 GspHex2Long (PCHAR
*Address
,
508 Hex
= HexValue (**Address
);
511 *Value
= (*Value
<< 4) | Hex
;
525 GspLong2Hex (PCHAR
*Address
,
530 Save
= (((Value
>> 0) & 0xf) << 24) |
531 (((Value
>> 8) & 0xf) << 16) |
532 (((Value
>> 16) & 0xf) << 8) |
533 (((Value
>> 24) & 0xf) << 0);
534 *Address
= GspMem2Hex ((PCHAR
) &Save
, *Address
, 4, FALSE
);
539 GspGetRegistersFromTrapFrame(PCHAR Address
,
540 PKTRAP_FRAME TrapFrame
)
549 Regs
= &GspRegisters
[0];
550 for (i
= 0; i
< NUMREGS
; i
++)
554 p
= (PULONG
) ((ULONG_PTR
) TrapFrame
+ Regs
[i
].OffsetInTF
);
557 else if (i
== EIP_REGNO
)
560 * This thread has not been sheduled yet so assume it
561 * is still in PsBeginThreadWithContextInternal().
563 Value
= (ULONG
) PsBeginThreadWithContextInternal
;
569 Buffer
= GspMem2Hex ((PCHAR
) &Value
, Buffer
, Regs
[i
].Size
, FALSE
);
575 GspSetRegistersInTrapFrame(PCHAR Address
,
576 PKTRAP_FRAME TrapFrame
)
588 Regs
= &GspRegisters
[0];
589 for (i
= 0; i
< NUMREGS
; i
++)
591 p
= (PULONG
) ((ULONG_PTR
) TrapFrame
+ Regs
[i
].OffsetInTF
);
593 Buffer
= GspHex2Mem (Buffer
, (PCHAR
) &Value
, Regs
[i
].Size
, FALSE
);
600 GspSetSingleRegisterInTrapFrame(PCHAR Address
,
602 PKTRAP_FRAME TrapFrame
)
610 p
= (PULONG
) ((ULONG_PTR
) TrapFrame
+ GspRegisters
[Number
].OffsetInTF
);
612 GspHex2Mem (Address
, (PCHAR
) &Value
, GspRegisters
[Number
].Size
, FALSE
);
618 GspFindThread(PCHAR Data
,
621 PETHREAD ThreadInfo
= NULL
;
623 if (strcmp (Data
, "-1") == 0)
628 else if (strcmp (Data
, "0") == 0)
630 /* Pick any thread, pick the first thread,
631 * which is what most people are interested in
633 ThreadInfo
= CONTAINING_RECORD (PiThreadListHead
.Flink
,
634 ETHREAD
, Tcb
.ThreadListEntry
);
639 PCHAR ptr
= &Data
[0];
641 GspHex2Long (&ptr
, (PLONG
) &ThreadId
);
643 if (!NT_SUCCESS (PsLookupThreadByThreadId ((PVOID
) ThreadId
, &ThreadInfo
)))
649 *Thread
= ThreadInfo
;
655 GspSetThread(PCHAR Request
)
658 PCHAR ptr
= &Request
[1];
662 case 'c': /* Run thread */
663 if (GspFindThread (ptr
, &ThreadInfo
))
665 GspOutBuffer
[0] = 'O';
666 GspOutBuffer
[1] = 'K';
667 GspRunThread
= ThreadInfo
;
671 GspOutBuffer
[0] = 'E';
674 case 'g': /* Debug thread */
675 if (GspFindThread (ptr
, &ThreadInfo
))
677 GspOutBuffer
[0] = 'O';
678 GspOutBuffer
[1] = 'K';
679 GspDbgThread
= ThreadInfo
;
683 GspOutBuffer
[0] = 'E';
693 GspQuery(PCHAR Request
)
698 Command
= strtok (Request
, ",");
699 if (strncmp (Command
, "C", 1) == 0)
701 PCHAR ptr
= &GspOutBuffer
[2];
703 /* Get current thread id */
704 GspOutBuffer
[0] = 'Q';
705 GspOutBuffer
[1] = 'C';
706 Value
= (ULONG
) GspDbgThread
->Cid
.UniqueThread
;
707 GspLong2Hex (&ptr
, Value
);
709 else if (strncmp (Command
, "fThreadInfo", 11) == 0)
711 PCHAR ptr
= &GspOutBuffer
[1];
713 /* Get first thread id */
714 GspOutBuffer
[0] = 'm';
715 GspEnumThread
= CONTAINING_RECORD (PiThreadListHead
.Flink
,
716 ETHREAD
, Tcb
.ThreadListEntry
);
717 Value
= (ULONG
) GspEnumThread
->Cid
.UniqueThread
;
718 GspLong2Hex (&ptr
, Value
);
720 else if (strncmp (Command
, "sThreadInfo", 11) == 0)
722 PCHAR ptr
= &GspOutBuffer
[1];
724 /* Get next thread id */
725 if ((GspEnumThread
) && (GspEnumThread
->Tcb
.ThreadListEntry
.Flink
!= PiThreadListHead
.Flink
))
727 GspEnumThread
= CONTAINING_RECORD (GspEnumThread
->Tcb
.ThreadListEntry
.Flink
,
728 ETHREAD
, Tcb
.ThreadListEntry
);
729 GspOutBuffer
[0] = 'm';
730 Value
= (ULONG
) GspEnumThread
->Cid
.UniqueThread
;
731 GspLong2Hex (&ptr
, Value
);
735 GspOutBuffer
[0] = '1';
738 else if (strncmp (Command
, "ThreadExtraInfo", 15) == 0)
741 PCHAR ptr
= &Command
[15];
743 /* Get thread information */
744 if (GspFindThread (ptr
, &ThreadInfo
))
746 PCHAR String
= GspThreadStates
[ThreadInfo
->Tcb
.State
];
747 GspMem2Hex (String
, &GspOutBuffer
[0], strlen (String
), FALSE
);
751 else if (strncmp (Command
, "L", 1) == 0)
753 PLIST_ENTRY CurrentEntry
;
755 ULONG MaxThreads
= 0;
757 ULONG ThreadCount
= 0;
760 GspHex2Mem (&Request
[1], (PCHAR
) &MaxThreads
, 2, TRUE
);
761 GspHex2Mem (&Request
[3], (PCHAR
) &Value
, 4, TRUE
);
762 GspHex2Mem (&Request
[11], (PCHAR
) &ThreadId
, 4, TRUE
);
764 GspOutBuffer
[0] = 'q';
765 GspOutBuffer
[1] = 'M';
767 GspMem2Hex ((PCHAR
) &Value
, &GspOutBuffer
[5], 4, TRUE
);
768 GspMem2Hex ((PCHAR
) &ThreadId
, &GspOutBuffer
[13], 4, TRUE
);
770 CurrentEntry
= PiThreadListHead
.Flink
;
771 while ((CurrentEntry
!= &PiThreadListHead
) && (ThreadCount
< MaxThreads
))
773 Current
= CONTAINING_RECORD (CurrentEntry
, ETHREAD
, Tcb
.ThreadListEntry
);
775 GspMem2Hex ((PCHAR
) &Value
, &GspOutBuffer
[21+ThreadCount
*16], 4, TRUE
);
776 Value
= (ULONG
) Current
->Cid
.UniqueThread
;
777 GspMem2Hex ((PCHAR
) &Value
, &GspOutBuffer
[21+ThreadCount
*16+8], 4, TRUE
);
778 CurrentEntry
= CurrentEntry
->Flink
;
782 if (CurrentEntry
!= &PiThreadListHead
)
784 GspOutBuffer
[4] = '0';
788 GspOutBuffer
[4] = '1';
791 GspMem2Hex ((PCHAR
) &ThreadCount
, &GspOutBuffer
[2], 1, TRUE
);
794 else if (strncmp (Command
, "Offsets", 7) == 0)
796 strcpy (GspOutBuffer
, "Text=0;Data=0;Bss=0");
801 GspQueryThreadStatus(PCHAR Request
)
804 PCHAR ptr
= &Request
[0];
806 if (GspFindThread (ptr
, &ThreadInfo
))
808 GspOutBuffer
[0] = 'O';
809 GspOutBuffer
[1] = 'K';
810 GspOutBuffer
[2] = '\0';
814 GspOutBuffer
[0] = 'E';
815 GspOutBuffer
[1] = '\0';
820 typedef struct _GsHwBreakPoint
828 GsHwBreakPoint GspBreakpoints
[4] =
837 GspCorrectHwBreakpoint()
839 ULONG BreakpointNumber
;
845 "movl %%db7, %0\n" : "=r" (dr7
) : );
848 ULONG addr0
, addr1
, addr2
, addr3
;
855 : "=r" (addr0
), "=r" (addr1
),
856 "=r" (addr2
), "=r" (addr3
) : );
859 for (BreakpointNumber
= 0; BreakpointNumber
< 3; BreakpointNumber
++)
861 Bit
= 2 << (BreakpointNumber
<< 1);
862 if (!(dr7
& Bit
) && GspBreakpoints
[BreakpointNumber
].Enabled
) {
865 dr7
&= ~(0xf0000 << (BreakpointNumber
<< 2));
866 dr7
|= (((GspBreakpoints
[BreakpointNumber
].Length
<< 2) |
867 GspBreakpoints
[BreakpointNumber
].Type
) << 16) << (BreakpointNumber
<< 2);
868 switch (BreakpointNumber
) {
870 asm volatile ("movl %0, %%dr0\n"
871 : : "r" (GspBreakpoints
[BreakpointNumber
].Address
) );
875 asm volatile ("movl %0, %%dr1\n"
876 : : "r" (GspBreakpoints
[BreakpointNumber
].Address
) );
880 asm volatile ("movl %0, %%dr2\n"
881 : : "r" (GspBreakpoints
[BreakpointNumber
].Address
) );
885 asm volatile ("movl %0, %%dr3\n"
886 : : "r" (GspBreakpoints
[BreakpointNumber
].Address
) );
890 else if ((dr7
& Bit
) && !GspBreakpoints
[BreakpointNumber
].Enabled
)
894 dr7
&= ~(0xf0000 << (BreakpointNumber
<< 2));
899 asm volatile ( "movl %0, %%db7\n" : : "r" (dr7
));
904 GspRemoveHwBreakpoint(ULONG BreakpointNumber
)
906 if (!GspBreakpoints
[BreakpointNumber
].Enabled
)
910 GspBreakpoints
[BreakpointNumber
].Enabled
= 0;
916 GspSetHwBreakpoint(ULONG BreakpointNumber
,
921 if (GspBreakpoints
[BreakpointNumber
].Enabled
)
925 GspBreakpoints
[BreakpointNumber
].Enabled
= TRUE
;
926 GspBreakpoints
[BreakpointNumber
].Type
= Type
;
927 GspBreakpoints
[BreakpointNumber
].Length
= Length
;
928 GspBreakpoints
[BreakpointNumber
].Address
= Address
;
934 * This function does all command procesing for interfacing to gdb.
937 KdEnterDebuggerException(PEXCEPTION_RECORD ExceptionRecord
,
939 PKTRAP_FRAME TrapFrame
)
948 /* FIXME: Stop on other CPUs too */
949 /* Disable hardware debugging while we are inside the stub */
950 __asm__("movl %0,%%db7" : /* no output */ : "r" (0));
952 /* reply to host that an exception has occurred */
953 SigVal
= GspComputeSignal (ExceptionRecord
->ExceptionCode
);
955 ptr
= &GspOutBuffer
[0];
957 *ptr
++ = 'T'; /* notify gdb with signo, PC, FP and SP */
958 *ptr
++ = HexChars
[(SigVal
>> 4) & 0xf];
959 *ptr
++ = HexChars
[SigVal
& 0xf];
961 *ptr
++ = HexChars
[ESP
];
963 ptr
= GspMem2Hex ((PCHAR
) &TrapFrame
->Esp
, ptr
, 4, 0); /* SP */
966 *ptr
++ = HexChars
[EBP
];
968 ptr
= GspMem2Hex ((PCHAR
) &TrapFrame
->Ebp
, ptr
, 4, 0); /* FP */
971 *ptr
++ = HexChars
[PC
];
973 ptr
= GspMem2Hex((PCHAR
) &TrapFrame
->Eip
, ptr
, 4, 0); /* PC */
978 GspPutPacket (&GspOutBuffer
[0]);
984 /* Zero the buffer now so we don't have to worry about the terminating zero character */
985 memset (GspOutBuffer
, 0, sizeof (GspInBuffer
));
986 ptr
= GspGetPacket ();
991 GspOutBuffer
[0] = 'S';
992 GspOutBuffer
[1] = HexChars
[SigVal
>> 4];
993 GspOutBuffer
[2] = HexChars
[SigVal
% 16];
997 GspRemoteDebug
= !GspRemoteDebug
; /* toggle debug flag */
999 case 'g': /* return the value of the CPU Registers */
1001 GspGetRegistersFromTrapFrame (&GspOutBuffer
[0], GspDbgThread
->Tcb
.TrapFrame
);
1003 GspGetRegistersFromTrapFrame (&GspOutBuffer
[0], TrapFrame
);
1005 case 'G': /* set the value of the CPU Registers - return OK */
1007 GspSetRegistersInTrapFrame (ptr
, GspDbgThread
->Tcb
.TrapFrame
);
1009 GspSetRegistersInTrapFrame (ptr
, TrapFrame
);
1010 strcpy (GspOutBuffer
, "OK");
1012 case 'P': /* set the value of a single CPU register - return OK */
1016 if ((GspHex2Long (&ptr
, &Register
)) && (*ptr
++ == '='))
1017 if ((Register
>= 0) && (Register
< NUMREGS
))
1020 GspSetSingleRegisterInTrapFrame (ptr
, Register
,
1021 GspDbgThread
->Tcb
.TrapFrame
);
1023 GspSetSingleRegisterInTrapFrame (ptr
, Register
, TrapFrame
);
1024 strcpy (GspOutBuffer
, "OK");
1028 strcpy (GspOutBuffer
, "E01");
1032 /* mAA..AA,LLLL Read LLLL bytes at address AA..AA */
1034 /* TRY TO READ %x,%x. IF SUCCEED, SET PTR = 0 */
1035 if (GspHex2Long (&ptr
, &Address
))
1036 if (*(ptr
++) == ',')
1037 if (GspHex2Long (&ptr
, &Length
))
1040 GspMemoryError
= FALSE
;
1041 GspMem2Hex ((PCHAR
) Address
, GspOutBuffer
, Length
, 1);
1044 strcpy (GspOutBuffer
, "E03");
1045 GspDebugError ("memory fault");
1051 strcpy (GspOutBuffer
, "E01");
1055 /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */
1057 /* TRY TO READ '%x,%x:'. IF SUCCEED, SET PTR = 0 */
1058 if (GspHex2Long (&ptr
, &Address
))
1059 if (*(ptr
++) == ',')
1060 if (GspHex2Long (&ptr
, &Length
))
1061 if (*(ptr
++) == ':')
1063 GspMemoryError
= FALSE
;
1064 GspHex2Mem (ptr
, (PCHAR
) Address
, Length
, TRUE
);
1068 strcpy (GspOutBuffer
, "E03");
1069 GspDebugError ("memory fault");
1073 strcpy (GspOutBuffer
, "OK");
1080 strcpy (GspOutBuffer
, "E02");
1084 /* cAA..AA Continue at address AA..AA(optional) */
1085 /* sAA..AA Step one instruction from AA..AA(optional) */
1090 ULONG BreakpointNumber
;
1093 /* try to read optional parameter, pc unchanged if no parm */
1094 if (GspHex2Long (&ptr
, &Address
))
1095 Context
->Eip
= Address
;
1097 NewPC
= Context
->Eip
;
1099 /* clear the trace bit */
1100 Context
->EFlags
&= 0xfffffeff;
1102 /* set the trace bit if we're Stepping */
1104 Context
->EFlags
|= 0x100;
1106 asm volatile ("movl %%db6, %0\n" : "=r" (dr6
) : );
1107 if (!(dr6
& 0x4000))
1109 for (BreakpointNumber
= 0; BreakpointNumber
< 4; ++BreakpointNumber
)
1111 if (dr6
& (1 << BreakpointNumber
))
1113 if (GspBreakpoints
[BreakpointNumber
].Type
== 0)
1115 /* Set restore flag */
1116 Context
->EFlags
|= 0x10000;
1122 GspCorrectHwBreakpoint();
1123 asm volatile ("movl %0, %%db6\n" : : "r" (0));
1125 return kdHandleException
;
1128 case 'k': /* kill the program */
1129 strcpy (GspOutBuffer
, "OK");
1131 /* kill the program */
1132 case 'H': /* Set thread */
1135 case 'q': /* Query */
1138 case 'T': /* Query thread status */
1139 GspQueryThreadStatus (ptr
);
1148 ptr
= &GspOutBuffer
[1];
1149 GspHex2Long (&ptr
, &Number
);
1151 GspHex2Long (&ptr
, &Type
);
1153 GspHex2Long (&ptr
, &Length
);
1155 GspHex2Long (&ptr
, &Address
);
1156 if (GspSetHwBreakpoint (Number
& 0x3, Type
& 0x3 , Length
& 0x3, Address
) == 0)
1158 strcpy (GspOutBuffer
, "OK");
1162 strcpy (GspOutBuffer
, "E");
1165 /* Remove hardware breakpoint */
1171 ptr
= &GspOutBuffer
[1];
1172 GspHex2Long(&ptr
, &Number
);
1173 if (GspRemoveHwBreakpoint (Number
& 0x3) == 0)
1175 strcpy (GspOutBuffer
, "OK");
1179 strcpy (GspOutBuffer
, "E");
1187 /* reply to the request */
1188 GspPutPacket (&GspOutBuffer
[0]);
1191 return kdDoNotHandleException
;
1197 GspBreakIn(PKINTERRUPT Interrupt
,
1198 PVOID ServiceContext
)
1200 PKTRAP_FRAME TrapFrame
;
1206 DPRINT ("Break In\n");
1209 while (KdPortGetByteEx (&GdbPortInfo
, &Value
))
1218 KeRaiseIrql (HIGH_LEVEL
, &OldIrql
);
1220 TrapFrame
= PsGetCurrentThread()->Tcb
.TrapFrame
;
1222 KeTrapFrameToContext (TrapFrame
, &Context
);
1224 KdEnterDebuggerException (NULL
, &Context
, TrapFrame
);
1226 KeContextToTrapFrame (&Context
, TrapFrame
);
1228 KeLowerIrql (OldIrql
);
1234 extern ULONG KdpPortIrq
;
1236 /* Initialize the GDB stub */
1238 KdGdbStubInit(ULONG Phase
)
1247 DbgPrint("Module 'hal.dll' loaded at 0x%.08x.\n", LdrHalBase
);
1249 GspInitialized
= TRUE
;
1250 GspRunThread
= PsGetCurrentThread();
1251 GspDbgThread
= PsGetCurrentThread();
1252 GspEnumThread
= NULL
;
1254 else if (Phase
== 1)
1256 /* Hook an interrupt handler to allow the debugger to break into
1258 MappedIrq
= HalGetInterruptVector (Internal
,
1265 Status
= IoConnectInterrupt(&GspInterrupt
,
1276 if (!NT_SUCCESS (Status
))
1278 DPRINT1("Could not connect to IRQ line %d (0x%x)\n",
1279 KdpPortIrq
, Status
);
1283 KdPortEnableInterrupts();
1285 DbgBreakPointWithStatus (DBG_STATUS_CONTROL_C
);
1289 /* This function will generate a breakpoint exception. It is used at the
1290 beginning of a program to sync up with a debugger and can be used
1291 otherwise as a quick means to stop program execution and "break" into
1295 KdGdbDebugPrint (LPSTR Message
)
1297 /* This can be quite annoying! */
1303 GspOutBuffer
[0] = 'O';
1304 GspOutBuffer
[1] = '\0';
1305 strcat (&GspOutBuffer
[0], Message
);
1306 Length
= strlen (Message
);
1307 GspOutBuffer
[2 + Length
] = '\n';
1308 GspOutBuffer
[3 + Length
] = '\0';
1309 GspPutPacketNoWait (&GspOutBuffer
[0]);