* Sync up to trunk head (r65394).
[reactos.git] / drivers / base / kdgdb / gdb_input.c
1 /*
2 * COPYRIGHT: GPL, see COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: drivers/base/kddll/gdb_input.c
5 * PURPOSE: Base functions for the kernel debugger.
6 */
7
8 #include "kdgdb.h"
9
10 /* LOCALS *********************************************************************/
11 static ULONG_PTR gdb_run_tid;
12 /* Keep track of where we are for qfThreadInfo/qsThreadInfo */
13 static LIST_ENTRY* CurrentProcessEntry;
14 static LIST_ENTRY* CurrentThreadEntry;
15
16 /* GLOBALS ********************************************************************/
17 UINT_PTR gdb_dbg_pid;
18 UINT_PTR gdb_dbg_tid;
19
20 /* PRIVATE FUNCTIONS **********************************************************/
21 static
22 UINT_PTR
23 hex_to_tid(char* buffer)
24 {
25 ULONG_PTR ret = 0;
26 char hex;
27 while (*buffer)
28 {
29 hex = hex_value(*buffer++);
30 if (hex < 0)
31 return ret;
32 ret <<= 4;
33 ret += hex;
34 }
35 return ret;
36 }
37 #define hex_to_pid hex_to_tid
38
39 static
40 ULONG64
41 hex_to_address(char* buffer)
42 {
43 ULONG64 ret = 0;
44 char hex;
45 while (*buffer)
46 {
47 hex = hex_value(*buffer++);
48 if (hex < 0)
49 return ret;
50 ret <<= 4;
51 ret += hex;
52 }
53 return ret;
54 }
55
56 /* H* packets */
57 static
58 void
59 handle_gdb_set_thread(void)
60 {
61 switch (gdb_input[1])
62 {
63 case 'c':
64 if (strcmp(&gdb_input[2], "-1") == 0)
65 gdb_run_tid = (ULONG_PTR)-1;
66 else
67 gdb_run_tid = hex_to_tid(&gdb_input[2]);
68 send_gdb_packet("OK");
69 break;
70 case 'g':
71 KDDBGPRINT("Setting debug thread: %s.\n", gdb_input);
72 if (strncmp(&gdb_input[2], "p-1", 3) == 0)
73 {
74 gdb_dbg_pid = (UINT_PTR)-1;
75 gdb_dbg_tid = (UINT_PTR)-1;
76 }
77 else
78 {
79 char* ptr = strstr(gdb_input, ".") + 1;
80 gdb_dbg_pid = hex_to_pid(&gdb_input[3]);
81 if (strncmp(ptr, "-1", 2) == 0)
82 gdb_dbg_tid = (UINT_PTR)-1;
83 else
84 gdb_dbg_tid = hex_to_tid(ptr);
85 }
86 send_gdb_packet("OK");
87 break;
88 default:
89 KDDBGPRINT("KDGBD: Unknown 'H' command: %s\n", gdb_input);
90 send_gdb_packet("");
91 }
92 }
93
94 KDSTATUS
95 gdb_receive_and_interpret_packet(
96 _Out_ DBGKD_MANIPULATE_STATE64* State,
97 _Out_ PSTRING MessageData,
98 _Out_ PULONG MessageLength,
99 _Inout_ PKD_CONTEXT KdContext)
100 {
101 KDSTATUS Status = gdb_receive_packet(KdContext);
102
103 if (Status != KdPacketReceived)
104 return Status;
105 return gdb_interpret_input(State, MessageData, MessageLength, KdContext);
106 }
107
108 static
109 void
110 handle_gdb_thread_alive(void)
111 {
112 ULONG_PTR Pid, Tid;
113 PETHREAD Thread;
114
115 Pid = hex_to_pid(&gdb_input[2]);
116 Tid = hex_to_tid(strstr(gdb_input, ".") + 1);
117
118 /* We cannot use PsLookupProcessThreadByCid as we could be running at any IRQL.
119 * So loop. */
120 KDDBGPRINT("Checking if p%p.%p is alive.\n", Pid, Tid);
121
122 Thread = find_thread(Pid, Tid);
123
124 if (Thread != NULL)
125 send_gdb_packet("OK");
126 else
127 send_gdb_packet("E03");
128 }
129
130 /* q* packets */
131 static
132 KDSTATUS
133 handle_gdb_query(
134 _Out_ DBGKD_MANIPULATE_STATE64* State,
135 _Out_ PSTRING MessageData,
136 _Out_ PULONG MessageLength,
137 _Inout_ PKD_CONTEXT KdContext)
138 {
139 if (strncmp(gdb_input, "qSupported:", 11) == 0)
140 {
141 send_gdb_packet("PacketSize=4096;multiprocess+;");
142 return gdb_receive_and_interpret_packet(State, MessageData, MessageLength, KdContext);
143 }
144
145 if (strncmp(gdb_input, "qAttached", 9) == 0)
146 {
147 /* Say no: We didn't attach, we create the process! */
148 send_gdb_packet("0");
149 return gdb_receive_and_interpret_packet(State, MessageData, MessageLength, KdContext);
150 }
151
152 if (strncmp(gdb_input, "qRcmd,", 6) == 0)
153 {
154 send_gdb_packet("OK");
155 return gdb_receive_and_interpret_packet(State, MessageData, MessageLength, KdContext);
156 }
157
158 if (strcmp(gdb_input, "qC") == 0)
159 {
160 char gdb_out[64];
161 sprintf(gdb_out, "QC:p%"PRIxPTR".%"PRIxPTR";",
162 handle_to_gdb_pid(PsGetThreadProcessId((PETHREAD)(ULONG_PTR)CurrentStateChange.Thread)),
163 handle_to_gdb_tid(PsGetThreadId((PETHREAD)(ULONG_PTR)CurrentStateChange.Thread)));
164 send_gdb_packet(gdb_out);
165 return gdb_receive_and_interpret_packet(State, MessageData, MessageLength, KdContext);
166 }
167
168 if ((strncmp(gdb_input, "qfThreadInfo", 12) == 0)
169 || (strncmp(gdb_input, "qsThreadInfo", 12) == 0))
170 {
171 BOOLEAN FirstThread = TRUE;
172 PEPROCESS Process;
173 PETHREAD Thread;
174 char gdb_out[1024];
175 char* ptr = gdb_out;
176 BOOLEAN Resuming = strncmp(gdb_input, "qsThreadInfo", 12) == 0;
177
178 if (Resuming)
179 {
180 if (CurrentProcessEntry == (LIST_ENTRY*)1)
181 {
182 /* We're done */
183 send_gdb_packet("l");
184 CurrentProcessEntry = NULL;
185 return gdb_receive_and_interpret_packet(State, MessageData, MessageLength, KdContext);
186 }
187
188 if (CurrentThreadEntry == NULL)
189 CurrentProcessEntry = CurrentProcessEntry->Flink;
190 }
191 else
192 CurrentProcessEntry = ProcessListHead->Flink;
193
194 if ((CurrentProcessEntry == ProcessListHead) ||
195 (CurrentProcessEntry == NULL)) /* Ps is not initialized */
196 {
197 /* We're almost done. Tell GDB about the idle thread */
198 send_gdb_packet("mp1.1");
199 CurrentProcessEntry = (LIST_ENTRY*)1;
200 return gdb_receive_and_interpret_packet(State, MessageData, MessageLength, KdContext);
201 }
202
203 Process = CONTAINING_RECORD(CurrentProcessEntry, EPROCESS, ActiveProcessLinks);
204
205 if (Resuming && CurrentThreadEntry != NULL)
206 CurrentThreadEntry = CurrentThreadEntry->Flink;
207 else
208 CurrentThreadEntry = Process->ThreadListHead.Flink;
209
210 ptr = gdb_out;
211
212 *ptr++ = 'm';
213 /* List threads from this process */
214 for ( ;
215 CurrentThreadEntry != &Process->ThreadListHead;
216 CurrentThreadEntry = CurrentThreadEntry->Flink)
217 {
218 Thread = CONTAINING_RECORD(CurrentThreadEntry, ETHREAD, ThreadListEntry);
219
220 /* See if we should add a comma */
221 if (FirstThread)
222 {
223 FirstThread = FALSE;
224 }
225 else
226 {
227 *ptr++ = ',';
228 }
229
230 ptr += _snprintf(ptr, 1024 - (ptr - gdb_out),
231 "p%p.%p",
232 handle_to_gdb_pid(Process->UniqueProcessId),
233 handle_to_gdb_tid(Thread->Cid.UniqueThread));
234 if (ptr > (gdb_out + 1024))
235 {
236 /* send what we got */
237 send_gdb_packet(gdb_out);
238 /* GDB can ask anything at this point, it isn't necessarily a qsThreadInfo packet */
239 return gdb_receive_and_interpret_packet(State, MessageData, MessageLength, KdContext);
240 }
241 }
242
243 /* send the list for this process */
244 send_gdb_packet(gdb_out);
245 CurrentThreadEntry = NULL;
246 /* GDB can ask anything at this point, it isn't necessarily a qsThreadInfo packet */
247 return gdb_receive_and_interpret_packet(State, MessageData, MessageLength, KdContext);
248 }
249
250 KDDBGPRINT("KDGDB: Unknown query: %s\n", gdb_input);
251 send_gdb_packet("");
252 return gdb_receive_and_interpret_packet(State, MessageData, MessageLength, KdContext);
253 }
254
255 #if 0
256 static
257 KDSTATUS
258 handle_gdb_registers(
259 _Out_ DBGKD_MANIPULATE_STATE64* State,
260 _Out_ PSTRING MessageData,
261 _Out_ PULONG MessageLength)
262 {
263 /*
264 if (gdb_dbg_thread)
265 KDDBGPRINT("Should get registers from other thread!\n");
266 */
267
268 State->ApiNumber = DbgKdGetContextApi;
269 State->ReturnStatus = STATUS_SUCCESS; /* ? */
270 State->Processor = CurrentStateChange.Processor;
271 State->ProcessorLevel = CurrentStateChange.ProcessorLevel;
272 if (MessageData)
273 MessageData->Length = 0;
274 *MessageLength = 0;
275 return KdPacketReceived;
276 }
277 #endif
278
279 static
280 void
281 ReadMemorySendHandler(
282 _In_ ULONG PacketType,
283 _In_ PSTRING MessageHeader,
284 _In_ PSTRING MessageData)
285 {
286 DBGKD_MANIPULATE_STATE64* State = (DBGKD_MANIPULATE_STATE64*)MessageHeader->Buffer;
287
288 if (PacketType != PACKET_TYPE_KD_STATE_MANIPULATE)
289 {
290 // KdAssert
291 KDDBGPRINT("Wrong packet type (%lu) received after DbgKdReadVirtualMemoryApi request.\n", PacketType);
292 while (1);
293 }
294
295 if (State->ApiNumber != DbgKdReadVirtualMemoryApi)
296 {
297 KDDBGPRINT("Wrong API number (%lu) after DbgKdReadVirtualMemoryApi request.\n", State->ApiNumber);
298 }
299
300 /* Check status */
301 if (!NT_SUCCESS(State->ReturnStatus))
302 send_gdb_ntstatus(State->ReturnStatus);
303 else
304 send_gdb_memory(MessageData->Buffer, MessageData->Length);
305 KdpSendPacketHandler = NULL;
306 KdpManipulateStateHandler = NULL;
307
308 /* Reset the TLB */
309 if ((gdb_dbg_pid != 0) && gdb_pid_to_handle(gdb_dbg_pid) != PsGetCurrentProcessId())
310 {
311 __writecr3(PsGetCurrentProcess()->Pcb.DirectoryTableBase[0]);
312 }
313 }
314
315 static
316 KDSTATUS
317 handle_gdb_read_mem(
318 _Out_ DBGKD_MANIPULATE_STATE64* State,
319 _Out_ PSTRING MessageData,
320 _Out_ PULONG MessageLength,
321 _Inout_ PKD_CONTEXT KdContext)
322 {
323 State->ApiNumber = DbgKdReadVirtualMemoryApi;
324 State->ReturnStatus = STATUS_SUCCESS; /* ? */
325 State->Processor = CurrentStateChange.Processor;
326 State->ProcessorLevel = CurrentStateChange.ProcessorLevel;
327 if (MessageData)
328 MessageData->Length = 0;
329 *MessageLength = 0;
330
331 /* Set the TLB according to the process being read. Pid 0 means any process. */
332 if ((gdb_dbg_pid != 0) && gdb_pid_to_handle(gdb_dbg_pid) != PsGetCurrentProcessId())
333 {
334 PEPROCESS AttachedProcess = find_process(gdb_dbg_pid);
335 if (AttachedProcess == NULL)
336 {
337 KDDBGPRINT("The current GDB debug thread is invalid!");
338 send_gdb_packet("E03");
339 return gdb_receive_and_interpret_packet(State, MessageData, MessageLength, KdContext);
340 }
341 __writecr3(AttachedProcess->Pcb.DirectoryTableBase[0]);
342 }
343
344 State->u.ReadMemory.TargetBaseAddress = hex_to_address(&gdb_input[1]);
345 State->u.ReadMemory.TransferCount = hex_to_address(strstr(&gdb_input[1], ",") + 1);
346
347 /* KD will reply with KdSendPacket. Catch it */
348 KdpSendPacketHandler = ReadMemorySendHandler;
349
350 return KdPacketReceived;
351 }
352
353 static
354 KDSTATUS
355 handle_gdb_v(
356 _Out_ DBGKD_MANIPULATE_STATE64* State,
357 _Out_ PSTRING MessageData,
358 _Out_ PULONG MessageLength,
359 _Inout_ PKD_CONTEXT KdContext)
360 {
361 if (strncmp(gdb_input, "vCont", 5) == 0)
362 {
363 if (gdb_input[5] == '?')
364 {
365 KDSTATUS Status;
366 /* Report what we support */
367 send_gdb_packet("vCont;c;C;s;S");
368 Status = gdb_receive_packet(KdContext);
369 if (Status != KdPacketReceived)
370 return Status;
371 return gdb_interpret_input(State, MessageData, MessageLength, KdContext);
372 }
373
374 if (strcmp(gdb_input, "vCont;c") == 0)
375 {
376 DBGKM_EXCEPTION64* Exception = NULL;
377
378 /* Tell GDB everything is fine, we will handle it */
379 send_gdb_packet("OK");
380
381 if (CurrentStateChange.NewState == DbgKdExceptionStateChange)
382 Exception = &CurrentStateChange.u.Exception;
383
384 /* See if we should update the program counter (unlike windbg, gdb doesn't do it for us) */
385 if (Exception && (Exception->ExceptionRecord.ExceptionCode == STATUS_BREAKPOINT)
386 && (Exception->ExceptionRecord.ExceptionInformation[0] == 0))
387 {
388 ULONG_PTR ProgramCounter;
389
390 /* So we must get past the breakpoint instruction */
391 ProgramCounter = KdpGetContextPc(&CurrentContext);
392 KdpSetContextPc(&CurrentContext, ProgramCounter + KD_BREAKPOINT_SIZE);
393
394 SetContextManipulateHandler(State, MessageData, MessageLength, KdContext);
395 KdpManipulateStateHandler = ContinueManipulateStateHandler;
396 return KdPacketReceived;
397 }
398
399 return ContinueManipulateStateHandler(State, MessageData, MessageLength, KdContext);
400 }
401 }
402
403 KDDBGPRINT("Unhandled 'v' packet: %s\n", gdb_input);
404 return KdPacketReceived;
405 }
406
407 /* GLOBAL FUNCTIONS ***********************************************************/
408 KDSTATUS
409 gdb_interpret_input(
410 _Out_ DBGKD_MANIPULATE_STATE64* State,
411 _Out_ PSTRING MessageData,
412 _Out_ PULONG MessageLength,
413 _Inout_ PKD_CONTEXT KdContext)
414 {
415 switch (gdb_input[0])
416 {
417 case '?':
418 /* Send the Status */
419 gdb_send_exception();
420 break;
421 case 'g':
422 return gdb_send_registers(State, MessageData, MessageLength, KdContext);
423 case 'H':
424 handle_gdb_set_thread();
425 break;
426 case 'm':
427 return handle_gdb_read_mem(State, MessageData, MessageLength, KdContext);
428 case 'p':
429 return gdb_send_register(State, MessageData, MessageLength, KdContext);
430 case 'q':
431 return handle_gdb_query(State, MessageData, MessageLength, KdContext);
432 case 'T':
433 handle_gdb_thread_alive();
434 break;
435 case 'v':
436 return handle_gdb_v(State, MessageData, MessageLength, KdContext);
437 default:
438 /* We don't know how to handle this request. Maybe this is something for KD */
439 State->ReturnStatus = STATUS_NOT_SUPPORTED;
440 KDDBGPRINT("Unsupported GDB command: %s.\n", gdb_input);
441 return KdPacketReceived;
442 }
443 return gdb_receive_and_interpret_packet(State, MessageData, MessageLength, KdContext);
444 }