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