xref: /reactos/drivers/base/kdgdb/gdb_send.c (revision 34593d93)
1 /*
2  * COPYRIGHT:       GPL, see COPYING in the top level directory
3  * PROJECT:         ReactOS kernel
4  * FILE:            drivers/base/kddll/gdb_send.c
5  * PURPOSE:         Base functions for the kernel debugger.
6  */
7 
8 #include "kdgdb.h"
9 
10 /* LOCALS *********************************************************************/
11 const char hex_chars[] = "0123456789abcdef";
12 static CHAR currentChecksum = 0;
13 
14 /* PRIVATE FUNCTIONS **********************************************************/
15 static
16 char*
exception_code_to_gdb(NTSTATUS code,char * out)17 exception_code_to_gdb(NTSTATUS code, char* out)
18 {
19     unsigned char SigVal;
20 
21     switch (code)
22     {
23     case STATUS_INTEGER_DIVIDE_BY_ZERO:
24         SigVal = 8; /* divide by zero */
25         break;
26     case STATUS_SINGLE_STEP:
27     case STATUS_BREAKPOINT:
28         SigVal = 5; /* breakpoint */
29         break;
30     case STATUS_INTEGER_OVERFLOW:
31     case STATUS_ARRAY_BOUNDS_EXCEEDED:
32         SigVal = 16; /* bound instruction */
33         break;
34     case STATUS_ILLEGAL_INSTRUCTION:
35         SigVal = 4; /* Invalid opcode */
36         break;
37     case STATUS_STACK_OVERFLOW:
38     case STATUS_DATATYPE_MISALIGNMENT:
39     case STATUS_ACCESS_VIOLATION:
40         SigVal = 11; /* access violation */
41         break;
42     default:
43         SigVal = 7; /* "software generated" */
44     }
45     *out++ = hex_chars[(SigVal >> 4) & 0xf];
46     *out++ = hex_chars[SigVal & 0xf];
47     return out;
48 }
49 
50 /* GLOBAL FUNCTIONS ***********************************************************/
51 void
start_gdb_packet(void)52 start_gdb_packet(void)
53 {
54     /* Start the start byte and begin checksum calculation */
55     KdpSendByte('$');
56     currentChecksum = 0;
57 }
58 
59 void
send_gdb_partial_packet(_In_ const CHAR * Buffer)60 send_gdb_partial_packet(_In_ const CHAR* Buffer)
61 {
62     const CHAR* ptr = Buffer;
63 
64     /* Update check sum and send */
65     while (*ptr)
66     {
67         currentChecksum += *ptr;
68         KdpSendByte(*ptr++);
69     }
70 }
71 
72 
73 KDSTATUS
finish_gdb_packet(void)74 finish_gdb_packet(void)
75 {
76     UCHAR ack;
77     KDSTATUS Status;
78 
79     /* Send finish byte and append checksum */
80     KdpSendByte('#');
81     KdpSendByte(hex_chars[(currentChecksum >> 4) & 0xf]);
82     KdpSendByte(hex_chars[currentChecksum & 0xf]);
83 
84     /* Wait for acknowledgement */
85     Status = KdpReceiveByte(&ack);
86 
87     if (Status != KdPacketReceived)
88     {
89         KD_DEBUGGER_NOT_PRESENT = TRUE;
90         return Status;
91     }
92 
93     if (ack != '+')
94         return KdPacketNeedsResend;
95 
96     return KdPacketReceived;
97 }
98 
99 KDSTATUS
send_gdb_packet(_In_ const CHAR * Buffer)100 send_gdb_packet(_In_ const CHAR* Buffer)
101 {
102     start_gdb_packet();
103     send_gdb_partial_packet(Buffer);
104     return finish_gdb_packet();
105 }
106 
107 ULONG
send_gdb_partial_binary(_In_ const VOID * Buffer,_In_ size_t Length)108 send_gdb_partial_binary(
109     _In_ const VOID* Buffer,
110     _In_ size_t Length)
111 {
112     const UCHAR* ptr = Buffer;
113     ULONG Sent = Length;
114 
115     while(Length--)
116     {
117         UCHAR Byte = *ptr++;
118 
119         switch (Byte)
120         {
121             case 0x7d:
122             case 0x23:
123             case 0x24:
124             case 0x2a:
125                 currentChecksum += 0x7d;
126                 KdpSendByte(0x7d);
127                 Byte ^= 0x20;
128                 Sent++;
129             /* Fall-through */
130             default:
131                 currentChecksum += Byte;
132                 KdpSendByte(Byte);
133         }
134     }
135 
136     return Sent;
137 }
138 
139 void
send_gdb_partial_memory(_In_ const VOID * Buffer,_In_ size_t Length)140 send_gdb_partial_memory(
141     _In_ const VOID* Buffer,
142     _In_ size_t Length)
143 {
144     const UCHAR* ptr = Buffer;
145     CHAR gdb_out[3];
146 
147     gdb_out[2] = '\0';
148 
149     while(Length--)
150     {
151         gdb_out[0] = hex_chars[(*ptr >> 4) & 0xf];
152         gdb_out[1] = hex_chars[*ptr++ & 0xf];
153         send_gdb_partial_packet(gdb_out);
154     }
155 }
156 
157 KDSTATUS
send_gdb_memory(_In_ const VOID * Buffer,_In_ size_t Length)158 send_gdb_memory(
159     _In_ const VOID* Buffer,
160     _In_ size_t Length)
161 {
162     start_gdb_packet();
163     send_gdb_partial_memory(Buffer, Length);
164     return finish_gdb_packet();
165 }
166 
167 KDSTATUS
gdb_send_debug_io(_In_ PSTRING String,_In_ BOOLEAN WithPrefix)168 gdb_send_debug_io(
169     _In_ PSTRING String,
170     _In_ BOOLEAN WithPrefix)
171 {
172     CHAR gdb_out[3];
173     CHAR* ptr = String->Buffer;
174     USHORT Length = String->Length;
175 
176     gdb_out[2] = '\0';
177 
178     start_gdb_packet();
179 
180     if (WithPrefix)
181     {
182         send_gdb_partial_packet("O");
183     }
184 
185     /* Send the data */
186     while (Length--)
187     {
188         gdb_out[0] = hex_chars[(*ptr >> 4) & 0xf];
189         gdb_out[1] = hex_chars[*ptr++ & 0xf];
190         send_gdb_partial_packet(gdb_out);
191     }
192 
193     return finish_gdb_packet();
194 }
195 
196 KDSTATUS
gdb_send_exception()197 gdb_send_exception()
198 {
199     char gdb_out[1024];
200     char* ptr = gdb_out;
201     PETHREAD Thread = (PETHREAD)(ULONG_PTR)CurrentStateChange.Thread;
202 
203     /* Report to GDB */
204     *ptr++ = 'T';
205 
206     if (CurrentStateChange.NewState == DbgKdExceptionStateChange)
207     {
208         EXCEPTION_RECORD64* ExceptionRecord = &CurrentStateChange.u.Exception.ExceptionRecord;
209         ptr = exception_code_to_gdb(ExceptionRecord->ExceptionCode, ptr);
210     }
211     else
212         ptr += sprintf(ptr, "05");
213 
214     if (CurrentStateChange.NewState == DbgKdLoadSymbolsStateChange)
215         ptr += sprintf(ptr, "library:");
216 
217 #if MONOPROCESS
218     ptr += sprintf(ptr, "thread:%" PRIxPTR ";",
219         handle_to_gdb_tid(PsGetThreadId(Thread)));
220 #else
221     ptr += sprintf(ptr, "thread:p%" PRIxPTR ".%" PRIxPTR ";",
222         handle_to_gdb_pid(PsGetThreadProcessId(Thread)),
223         handle_to_gdb_tid(PsGetThreadId(Thread)));
224 #endif
225 
226     ptr += sprintf(ptr, "core:%x;", CurrentStateChange.Processor);
227     return send_gdb_packet(gdb_out);
228 }
229 
230 void
send_gdb_ntstatus(_In_ NTSTATUS Status)231 send_gdb_ntstatus(
232     _In_ NTSTATUS Status)
233 {
234     /* Just build a EXX packet and send it */
235     char gdb_out[4];
236     gdb_out[0] = 'E';
237     exception_code_to_gdb(Status, &gdb_out[1]);
238     gdb_out[3] = '\0';
239     send_gdb_packet(gdb_out);
240 }
241