xref: /reactos/drivers/base/kdgdb/gdb_input.c (revision 6924b8ff)
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 static struct
13 {
14     ULONG_PTR Address;
15     ULONG Handle;
16 } BreakPointHandles[32];
17 
18 
19 /* GLOBALS ********************************************************************/
20 UINT_PTR gdb_dbg_pid;
21 UINT_PTR gdb_dbg_tid;
22 
23 static inline
24 KDSTATUS
25 LOOP_IF_SUCCESS(int x)
26 {
27     return (x == KdPacketReceived) ? (KDSTATUS)-1 : x;
28 }
29 
30 /* PRIVATE FUNCTIONS **********************************************************/
31 static
32 UINT_PTR
33 hex_to_tid(char* buffer)
34 {
35     ULONG_PTR ret = 0;
36     char hex;
37     while (*buffer)
38     {
39         hex = hex_value(*buffer++);
40         if (hex < 0)
41             return ret;
42         ret <<= 4;
43         ret += hex;
44     }
45     return ret;
46 }
47 #define hex_to_pid hex_to_tid
48 
49 static
50 ULONG64
51 hex_to_address(char* buffer)
52 {
53     ULONG64 ret = 0;
54     char hex;
55     while (*buffer)
56     {
57         hex = hex_value(*buffer++);
58         if (hex < 0)
59             return ret;
60         ret <<= 4;
61         ret += hex;
62     }
63     return ret;
64 }
65 
66 /* H* packets */
67 static
68 KDSTATUS
69 handle_gdb_set_thread(void)
70 {
71     KDSTATUS Status;
72 
73     switch (gdb_input[1])
74     {
75     case 'c':
76         if (strcmp(&gdb_input[2], "-1") == 0)
77             gdb_run_tid = (ULONG_PTR)-1;
78         else
79             gdb_run_tid = hex_to_tid(&gdb_input[2]);
80         Status = send_gdb_packet("OK");
81         break;
82     case 'g':
83         KDDBGPRINT("Setting debug thread: %s.\n", gdb_input);
84 #if MONOPROCESS
85         gdb_dbg_pid = 0;
86         if (strncmp(&gdb_input[2], "-1", 2) == 0)
87         {
88             gdb_dbg_tid = (UINT_PTR)-1;
89         }
90         else
91         {
92             gdb_dbg_tid = hex_to_tid(&gdb_input[2]);
93         }
94 #else
95         if (strncmp(&gdb_input[2], "p-1", 3) == 0)
96         {
97             gdb_dbg_pid = (UINT_PTR)-1;
98             gdb_dbg_tid = (UINT_PTR)-1;
99         }
100         else
101         {
102             char* ptr = strstr(gdb_input, ".") + 1;
103             gdb_dbg_pid = hex_to_pid(&gdb_input[3]);
104             if (strncmp(ptr, "-1", 2) == 0)
105                 gdb_dbg_tid = (UINT_PTR)-1;
106             else
107                 gdb_dbg_tid = hex_to_tid(ptr);
108         }
109 #endif
110         Status = send_gdb_packet("OK");
111         break;
112     default:
113         KDDBGPRINT("KDGBD: Unknown 'H' command: %s\n", gdb_input);
114         Status = send_gdb_packet("");
115     }
116 
117     return Status;
118 }
119 
120 static
121 KDSTATUS
122 handle_gdb_thread_alive(void)
123 {
124     ULONG_PTR Pid, Tid;
125     PETHREAD Thread;
126     KDSTATUS Status;
127 
128 #if MONOPROCESS
129     Pid = 0;
130     Tid = hex_to_tid(&gdb_input[1]);
131 
132     KDDBGPRINT("Checking if %p is alive.\n", Tid);
133 
134 #else
135     Pid = hex_to_pid(&gdb_input[2]);
136     Tid = hex_to_tid(strstr(gdb_input, ".") + 1);
137 
138     /* We cannot use PsLookupProcessThreadByCid as we could be running at any IRQL.
139      * So loop. */
140     KDDBGPRINT("Checking if p%p.%p is alive.\n", Pid, Tid);
141 #endif
142 
143     Thread = find_thread(Pid, Tid);
144 
145     if (Thread != NULL)
146         Status = send_gdb_packet("OK");
147     else
148         Status = send_gdb_packet("E03");
149 
150     return Status;
151 }
152 
153 /* q* packets */
154 static
155 KDSTATUS
156 handle_gdb_query(void)
157 {
158     if (strncmp(gdb_input, "qSupported:", 11) == 0)
159     {
160 #if MONOPROCESS
161         return send_gdb_packet("PacketSize=1000;qXfer:libraries:read+;");
162 #else
163         return send_gdb_packet("PacketSize=1000;multiprocess+;qXfer:libraries:read+;");
164 #endif
165     }
166 
167     if (strncmp(gdb_input, "qAttached", 9) == 0)
168     {
169 #if MONOPROCESS
170         return send_gdb_packet("1");
171 #else
172         UINT_PTR queried_pid = hex_to_pid(&gdb_input[10]);
173         /* Let's say we created system process */
174         if (gdb_pid_to_handle(queried_pid) == NULL)
175             return send_gdb_packet("0");
176         else
177             return send_gdb_packet("1");
178 #endif
179     }
180 
181     if (strncmp(gdb_input, "qRcmd,", 6) == 0)
182     {
183         return send_gdb_packet("OK");
184     }
185 
186     if (strcmp(gdb_input, "qC") == 0)
187     {
188         char gdb_out[64];
189 #if MONOPROCESS
190         sprintf(gdb_out, "QC:%"PRIxPTR";",
191             handle_to_gdb_tid(PsGetThreadId((PETHREAD)(ULONG_PTR)CurrentStateChange.Thread)));
192 #else
193         sprintf(gdb_out, "QC:p%"PRIxPTR".%"PRIxPTR";",
194             handle_to_gdb_pid(PsGetThreadProcessId((PETHREAD)(ULONG_PTR)CurrentStateChange.Thread)),
195             handle_to_gdb_tid(PsGetThreadId((PETHREAD)(ULONG_PTR)CurrentStateChange.Thread)));
196 #endif
197         return send_gdb_packet(gdb_out);
198     }
199 
200     if (strncmp(gdb_input, "qfThreadInfo", 12) == 0)
201     {
202         PEPROCESS Process;
203         char gdb_out[40];
204         LIST_ENTRY* CurrentProcessEntry;
205 
206         CurrentProcessEntry = ProcessListHead->Flink;
207         if (CurrentProcessEntry == NULL) /* Ps is not initialized */
208         {
209 #if MONOPROCESS
210             return send_gdb_packet("m1");
211 #else
212             return send_gdb_packet("mp1.1");
213 #endif
214         }
215 
216         /* We will push threads as we find them */
217         start_gdb_packet();
218 
219         /* Start with the system thread */
220 #if MONOPROCESS
221         send_gdb_partial_packet("m1");
222 #else
223         send_gdb_partial_packet("mp1.1");
224 #endif
225 
226         /* List all the processes */
227         for ( ;
228             CurrentProcessEntry != ProcessListHead;
229             CurrentProcessEntry = CurrentProcessEntry->Flink)
230         {
231             LIST_ENTRY* CurrentThreadEntry;
232 
233             Process = CONTAINING_RECORD(CurrentProcessEntry, EPROCESS, ActiveProcessLinks);
234 
235             /* List threads from this process */
236             for ( CurrentThreadEntry = Process->ThreadListHead.Flink;
237                  CurrentThreadEntry != &Process->ThreadListHead;
238                  CurrentThreadEntry = CurrentThreadEntry->Flink)
239             {
240                 PETHREAD Thread = CONTAINING_RECORD(CurrentThreadEntry, ETHREAD, ThreadListEntry);
241 
242 #if MONOPROCESS
243                 _snprintf(gdb_out, 40, ",%p", handle_to_gdb_tid(Thread->Cid.UniqueThread));
244 #else
245                 _snprintf(gdb_out, 40, ",p%p.%p",
246                     handle_to_gdb_pid(Process->UniqueProcessId),
247                     handle_to_gdb_tid(Thread->Cid.UniqueThread));
248 #endif
249                 send_gdb_partial_packet(gdb_out);
250             }
251         }
252 
253         return finish_gdb_packet();
254     }
255 
256     if (strncmp(gdb_input, "qsThreadInfo", 12) == 0)
257     {
258         /* We sent the whole thread list on first qfThreadInfo call */
259         return send_gdb_packet("l");
260     }
261 
262     if (strncmp(gdb_input, "qGetTIBAddr:", 12) == 0)
263     {
264         ULONG_PTR Pid, Tid;
265         PETHREAD Thread;
266 
267 #if MONOPROCESS
268         Pid = 0;
269         Tid = hex_to_tid(&gdb_input[12]);
270 
271         KDDBGPRINT(" %p.\n", Tid);
272 
273         Thread = find_thread(Pid, Tid);
274 #else
275         Pid = hex_to_pid(&gdb_input[13]);
276         Tid = hex_to_tid(strstr(&gdb_input[13], ".") + 1);
277 
278         /* We cannot use PsLookupProcessThreadByCid as we could be running at any IRQL.
279          * So loop. */
280         KDDBGPRINT(" p%p.%p.\n", Pid, Tid);
281         Thread = find_thread(Pid, Tid);
282 #endif
283         return send_gdb_memory(&Thread->Tcb.Teb, sizeof(Thread->Tcb.Teb));
284     }
285 
286     if (strncmp(gdb_input, "qThreadExtraInfo,", 17) == 0)
287     {
288         ULONG_PTR Pid, Tid;
289         PETHREAD Thread;
290         PEPROCESS Process;
291         char out_string[64];
292         STRING String = {0, 64, out_string};
293 
294         KDDBGPRINT("Giving extra info for");
295 
296 #if MONOPROCESS
297         Pid = 0;
298         Tid = hex_to_tid(&gdb_input[17]);
299 
300         KDDBGPRINT(" %p.\n", Tid);
301 
302         Thread = find_thread(Pid, Tid);
303         Process = CONTAINING_RECORD(Thread->Tcb.Process, EPROCESS, Pcb);
304 #else
305         Pid = hex_to_pid(&gdb_input[18]);
306         Tid = hex_to_tid(strstr(&gdb_input[18], ".") + 1);
307 
308         /* We cannot use PsLookupProcessThreadByCid as we could be running at any IRQL.
309          * So loop. */
310         KDDBGPRINT(" p%p.%p.\n", Pid, Tid);
311 
312         Process = find_process(Pid);
313         Thread = find_thread(Pid, Tid);
314 #endif
315 
316         if (PsGetThreadProcessId(Thread) == 0)
317         {
318             String.Length = sprintf(out_string, "SYSTEM");
319         }
320         else
321         {
322             String.Length = sprintf(out_string, "%.*s", 16, Process->ImageFileName);
323         }
324 
325         return gdb_send_debug_io(&String, FALSE);
326     }
327 
328     if (strcmp(gdb_input, "qTStatus") == 0)
329     {
330         /* No tracepoint support */
331         return send_gdb_packet("T0");
332     }
333 
334     if (strcmp(gdb_input, "qSymbol::") == 0)
335     {
336         /* No need */
337         return send_gdb_packet("OK");
338     }
339 
340     if (strncmp(gdb_input, "qXfer:libraries:read::", 22) == 0)
341     {
342         static LIST_ENTRY* CurrentEntry = NULL;
343         char str_helper[256];
344         char name_helper[64];
345         ULONG_PTR Offset = hex_to_address(&gdb_input[22]);
346         ULONG_PTR ToSend = hex_to_address(strstr(&gdb_input[22], ",") + 1);
347         ULONG Sent = 0;
348         static BOOLEAN allDone = FALSE;
349 
350         KDDBGPRINT("KDGDB: qXfer:libraries:read !\n");
351 
352         /* Start the packet */
353         start_gdb_packet();
354 
355         if (allDone)
356         {
357             send_gdb_partial_packet("l");
358             allDone = FALSE;
359             return finish_gdb_packet();
360         }
361 
362         send_gdb_partial_packet("m");
363         Sent++;
364 
365         /* Are we starting ? */
366         if (Offset == 0)
367         {
368             Sent += send_gdb_partial_binary("<?xml version=\"1.0\"?>", 21);
369             Sent += send_gdb_partial_binary("<library-list>", 14);
370 
371             CurrentEntry = ModuleListHead->Flink;
372 
373             if (!CurrentEntry)
374             {
375                 /* Ps is not initialized. Send end of XML data or mark that we are finished. */
376                 Sent += send_gdb_partial_binary("</library-list>", 15);
377                 allDone = TRUE;
378                 return finish_gdb_packet();
379             }
380         }
381 
382         for ( ;
383             CurrentEntry != ModuleListHead;
384             CurrentEntry = CurrentEntry->Flink)
385         {
386             PLDR_DATA_TABLE_ENTRY TableEntry = CONTAINING_RECORD(CurrentEntry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
387             PVOID DllBase = (PVOID)((ULONG_PTR)TableEntry->DllBase + 0x1000);
388             LONG mem_length;
389             USHORT i;
390 
391             /* Convert names to lower case. Yes this _is_ ugly */
392             for (i = 0; i < (TableEntry->BaseDllName.Length / sizeof(WCHAR)); i++)
393             {
394                 name_helper[i] = (char)TableEntry->BaseDllName.Buffer[i];
395                 if (name_helper[i] >= 'A' && name_helper[i] <= 'Z')
396                     name_helper[i] += 'a' - 'A';
397             }
398             name_helper[i] = 0;
399 
400             /* GDB doesn't load the file if you don't prefix it with a drive letter... */
401             mem_length = _snprintf(str_helper, 256, "<library name=\"C:\\%s\"><segment address=\"0x%p\"/></library>", &name_helper, DllBase);
402 
403             /* DLL name must be too long. */
404             if (mem_length < 0)
405             {
406                 KDDBGPRINT("Failed to report %wZ\n", &TableEntry->BaseDllName);
407                 continue;
408             }
409 
410             if ((Sent + mem_length) > ToSend)
411             {
412                 /* We're done for this pass */
413                 return finish_gdb_packet();
414             }
415 
416             Sent += send_gdb_partial_binary(str_helper, mem_length);
417         }
418 
419         if ((ToSend - Sent) > 15)
420         {
421             Sent += send_gdb_partial_binary("</library-list>", 15);
422             allDone = TRUE;
423         }
424 
425         return finish_gdb_packet();
426     }
427 
428     KDDBGPRINT("KDGDB: Unknown query: %s\n", gdb_input);
429     return send_gdb_packet("");
430 }
431 
432 #if 0
433 static
434 KDSTATUS
435 handle_gdb_registers(
436     _Out_ DBGKD_MANIPULATE_STATE64* State,
437     _Out_ PSTRING MessageData,
438     _Out_ PULONG MessageLength)
439 {
440     /*
441     if (gdb_dbg_thread)
442         KDDBGPRINT("Should get registers from other thread!\n");
443     */
444 
445     State->ApiNumber = DbgKdGetContextApi;
446     State->ReturnStatus = STATUS_SUCCESS; /* ? */
447     State->Processor = CurrentStateChange.Processor;
448     State->ProcessorLevel = CurrentStateChange.ProcessorLevel;
449     if (MessageData)
450         MessageData->Length = 0;
451     *MessageLength = 0;
452     return KdPacketReceived;
453 }
454 #endif
455 
456 static
457 BOOLEAN
458 ReadMemorySendHandler(
459     _In_ ULONG PacketType,
460     _In_ PSTRING MessageHeader,
461     _In_ PSTRING MessageData)
462 {
463     DBGKD_MANIPULATE_STATE64* State = (DBGKD_MANIPULATE_STATE64*)MessageHeader->Buffer;
464 
465     if (PacketType != PACKET_TYPE_KD_STATE_MANIPULATE)
466     {
467         // KdAssert
468         KDDBGPRINT("Wrong packet type (%lu) received after DbgKdReadVirtualMemoryApi request.\n", PacketType);
469         return FALSE;
470     }
471 
472     if (State->ApiNumber != DbgKdReadVirtualMemoryApi)
473     {
474         KDDBGPRINT("Wrong API number (%lu) after DbgKdReadVirtualMemoryApi request.\n", State->ApiNumber);
475         return FALSE;
476     }
477 
478     /* Check status. Allow to send partial data. */
479     if (!MessageData->Length && !NT_SUCCESS(State->ReturnStatus))
480         send_gdb_ntstatus(State->ReturnStatus);
481     else
482         send_gdb_memory(MessageData->Buffer, MessageData->Length);
483     KdpSendPacketHandler = NULL;
484     KdpManipulateStateHandler = NULL;
485 
486 #if MONOPROCESS
487     if (gdb_dbg_tid != 0)
488     /* Reset the TLB */
489 #else
490     if ((gdb_dbg_pid != 0) && gdb_pid_to_handle(gdb_dbg_pid) != PsGetCurrentProcessId())
491 #endif
492     {
493         /* Only do this if Ps is initialized */
494         if (ProcessListHead->Flink)
495             __writecr3(PsGetCurrentProcess()->Pcb.DirectoryTableBase[0]);
496     }
497 
498     return TRUE;
499 }
500 
501 static
502 KDSTATUS
503 handle_gdb_read_mem(
504     _Out_ DBGKD_MANIPULATE_STATE64* State,
505     _Out_ PSTRING MessageData,
506     _Out_ PULONG MessageLength,
507     _Inout_ PKD_CONTEXT KdContext)
508 {
509     State->ApiNumber = DbgKdReadVirtualMemoryApi;
510     State->ReturnStatus = STATUS_SUCCESS; /* ? */
511     State->Processor = CurrentStateChange.Processor;
512     State->ProcessorLevel = CurrentStateChange.ProcessorLevel;
513     if (MessageData)
514         MessageData->Length = 0;
515     *MessageLength = 0;
516 
517     /* Set the TLB according to the process being read. Pid 0 means any process. */
518 #if MONOPROCESS
519     if ((gdb_dbg_tid != 0) && gdb_tid_to_handle(gdb_dbg_tid) != PsGetCurrentThreadId())
520     {
521         PETHREAD AttachedThread = find_thread(0, gdb_dbg_tid);
522         PKPROCESS AttachedProcess;
523         if (AttachedThread == NULL)
524         {
525             KDDBGPRINT("The current GDB debug thread is invalid!");
526             return LOOP_IF_SUCCESS(send_gdb_packet("E03"));
527         }
528 
529         AttachedProcess = AttachedThread->Tcb.Process;
530         if (AttachedProcess == NULL)
531         {
532             KDDBGPRINT("The current GDB debug thread is invalid!");
533             return LOOP_IF_SUCCESS(send_gdb_packet("E03"));
534         }
535         __writecr3(AttachedProcess->DirectoryTableBase[0]);
536     }
537 #else
538     if ((gdb_dbg_pid != 0) && gdb_pid_to_handle(gdb_dbg_pid) != PsGetCurrentProcessId())
539     {
540         PEPROCESS AttachedProcess = find_process(gdb_dbg_pid);
541         if (AttachedProcess == NULL)
542         {
543             KDDBGPRINT("The current GDB debug thread is invalid!");
544             return LOOP_IF_SUCCESS(send_gdb_packet("E03"));
545         }
546         /* Only do this if Ps is initialized */
547         if (ProcessListHead->Flink)
548             __writecr3(AttachedProcess->Pcb.DirectoryTableBase[0]);
549     }
550 #endif
551 
552     State->u.ReadMemory.TargetBaseAddress = hex_to_address(&gdb_input[1]);
553     State->u.ReadMemory.TransferCount = hex_to_address(strstr(&gdb_input[1], ",") + 1);
554 
555     /* KD will reply with KdSendPacket. Catch it */
556     KdpSendPacketHandler = ReadMemorySendHandler;
557     return KdPacketReceived;
558 }
559 
560 static
561 BOOLEAN
562 WriteMemorySendHandler(
563     _In_ ULONG PacketType,
564     _In_ PSTRING MessageHeader,
565     _In_ PSTRING MessageData)
566 {
567     DBGKD_MANIPULATE_STATE64* State = (DBGKD_MANIPULATE_STATE64*)MessageHeader->Buffer;
568 
569     if (PacketType != PACKET_TYPE_KD_STATE_MANIPULATE)
570     {
571         // KdAssert
572         KDDBGPRINT("Wrong packet type (%lu) received after DbgKdWriteVirtualMemoryApi request.\n", PacketType);
573         return FALSE;
574     }
575 
576     if (State->ApiNumber != DbgKdWriteVirtualMemoryApi)
577     {
578         KDDBGPRINT("Wrong API number (%lu) after DbgKdWriteVirtualMemoryApi request.\n", State->ApiNumber);
579         return FALSE;
580     }
581 
582     /* Check status */
583     if (!NT_SUCCESS(State->ReturnStatus))
584         send_gdb_ntstatus(State->ReturnStatus);
585     else
586         send_gdb_packet("OK");
587     KdpSendPacketHandler = NULL;
588     KdpManipulateStateHandler = NULL;
589 
590 #if MONOPROCESS
591     if (gdb_dbg_tid != 0)
592     /* Reset the TLB */
593 #else
594     if ((gdb_dbg_pid != 0) && gdb_pid_to_handle(gdb_dbg_pid) != PsGetCurrentProcessId())
595 #endif
596     {
597         /* Only do this if Ps is initialized */
598         if (ProcessListHead->Flink)
599             __writecr3(PsGetCurrentProcess()->Pcb.DirectoryTableBase[0]);
600     }
601     return TRUE;
602 }
603 
604 static
605 KDSTATUS
606 handle_gdb_write_mem(
607     _Out_ DBGKD_MANIPULATE_STATE64* State,
608     _Out_ PSTRING MessageData,
609     _Out_ PULONG MessageLength,
610     _Inout_ PKD_CONTEXT KdContext)
611 {
612     /* Maximal input buffer is 0x1000. Each byte is encoded on two bytes by GDB */
613     static UCHAR OutBuffer[0x800];
614     ULONG BufferLength;
615     char* blob_ptr;
616     UCHAR* OutPtr;
617 
618     State->ApiNumber = DbgKdWriteVirtualMemoryApi;
619     State->ReturnStatus = STATUS_SUCCESS; /* ? */
620     State->Processor = CurrentStateChange.Processor;
621     State->ProcessorLevel = CurrentStateChange.ProcessorLevel;
622 
623     /* Set the TLB according to the process being read. Pid 0 means any process. */
624 #if MONOPROCESS
625     if ((gdb_dbg_tid != 0) && gdb_tid_to_handle(gdb_dbg_tid) != PsGetCurrentThreadId())
626     {
627         PETHREAD AttachedThread = find_thread(0, gdb_dbg_tid);
628         PKPROCESS AttachedProcess;
629         if (AttachedThread == NULL)
630         {
631             KDDBGPRINT("The current GDB debug thread is invalid!");
632             return LOOP_IF_SUCCESS(send_gdb_packet("E03"));
633         }
634 
635         AttachedProcess = AttachedThread->Tcb.Process;
636         if (AttachedProcess == NULL)
637         {
638             KDDBGPRINT("The current GDB debug thread is invalid!");
639             return LOOP_IF_SUCCESS(send_gdb_packet("E03"));
640         }
641         __writecr3(AttachedProcess->DirectoryTableBase[0]);
642     }
643 #else
644     if ((gdb_dbg_pid != 0) && gdb_pid_to_handle(gdb_dbg_pid) != PsGetCurrentProcessId())
645     {
646         PEPROCESS AttachedProcess = find_process(gdb_dbg_pid);
647         if (AttachedProcess == NULL)
648         {
649             KDDBGPRINT("The current GDB debug thread is invalid!");
650             return LOOP_IF_SUCCESS(send_gdb_packet("E03"));
651         }
652         /* Only do this if Ps is initialized */
653         if (ProcessListHead->Flink)
654             __writecr3(AttachedProcess->Pcb.DirectoryTableBase[0]);
655     }
656 #endif
657 
658     State->u.WriteMemory.TargetBaseAddress = hex_to_address(&gdb_input[1]);
659     BufferLength = hex_to_address(strstr(&gdb_input[1], ",") + 1);
660     if (BufferLength == 0)
661     {
662         /* Nothing to do */
663         return LOOP_IF_SUCCESS(send_gdb_packet("OK"));
664     }
665 
666     State->u.WriteMemory.TransferCount = BufferLength;
667     MessageData->Length = BufferLength;
668     MessageData->Buffer = (CHAR*)OutBuffer;
669 
670     OutPtr = OutBuffer;
671     blob_ptr = strstr(strstr(&gdb_input[1], ",") + 1, ":") + 1;
672     while (BufferLength)
673     {
674         if (BufferLength >= 4)
675         {
676             *((ULONG*)OutPtr) = *((ULONG*)blob_ptr);
677             OutPtr += 4;
678             blob_ptr += 4;
679             BufferLength -= 4;
680         }
681         else if (BufferLength >= 2)
682         {
683             *((USHORT*)OutPtr) = *((USHORT*)blob_ptr);
684             OutPtr += 2;
685             blob_ptr += 2;
686             BufferLength -= 2;
687         }
688         else
689         {
690             *OutPtr++ = *blob_ptr++;
691             BufferLength--;
692         }
693     }
694 
695     /* KD will reply with KdSendPacket. Catch it */
696     KdpSendPacketHandler = WriteMemorySendHandler;
697     return KdPacketReceived;
698 }
699 
700 static
701 BOOLEAN
702 WriteBreakPointSendHandler(
703     _In_ ULONG PacketType,
704     _In_ PSTRING MessageHeader,
705     _In_ PSTRING MessageData)
706 {
707     DBGKD_MANIPULATE_STATE64* State = (DBGKD_MANIPULATE_STATE64*)MessageHeader->Buffer;
708 
709     if (PacketType != PACKET_TYPE_KD_STATE_MANIPULATE)
710     {
711         // KdAssert
712         KDDBGPRINT("Wrong packet type (%lu) received after DbgKdWriteBreakPointApi request.\n", PacketType);
713         return FALSE;
714     }
715 
716     if (State->ApiNumber != DbgKdWriteBreakPointApi)
717     {
718         KDDBGPRINT("Wrong API number (%lu) after DbgKdWriteBreakPointApi request.\n", State->ApiNumber);
719         return FALSE;
720     }
721 
722     /* Check status */
723     if (!NT_SUCCESS(State->ReturnStatus))
724     {
725         KDDBGPRINT("Inserting breakpoint failed!\n");
726         send_gdb_ntstatus(State->ReturnStatus);
727     }
728     else
729     {
730         /* Keep track of the address+handle couple */
731         ULONG i;
732         for (i = 0; i < (sizeof(BreakPointHandles) / sizeof(BreakPointHandles[0])); i++)
733         {
734             if (BreakPointHandles[i].Address == 0)
735             {
736                 BreakPointHandles[i].Address = (ULONG_PTR)State->u.WriteBreakPoint.BreakPointAddress;
737                 BreakPointHandles[i].Handle = State->u.WriteBreakPoint.BreakPointHandle;
738                 break;
739             }
740         }
741         send_gdb_packet("OK");
742     }
743     KdpSendPacketHandler = NULL;
744     KdpManipulateStateHandler = NULL;
745     return TRUE;
746 }
747 
748 static
749 KDSTATUS
750 handle_gdb_insert_breakpoint(
751     _Out_ DBGKD_MANIPULATE_STATE64* State,
752     _Out_ PSTRING MessageData,
753     _Out_ PULONG MessageLength,
754     _Inout_ PKD_CONTEXT KdContext)
755 {
756     State->ReturnStatus = STATUS_SUCCESS; /* ? */
757     State->Processor = CurrentStateChange.Processor;
758     State->ProcessorLevel = CurrentStateChange.ProcessorLevel;
759     if (MessageData)
760         MessageData->Length = 0;
761     *MessageLength = 0;
762 
763     switch (gdb_input[1])
764     {
765         case '0':
766         {
767             ULONG_PTR Address = hex_to_address(&gdb_input[3]);
768             ULONG i;
769             BOOLEAN HasFreeSlot = FALSE;
770 
771             KDDBGPRINT("Inserting breakpoint at %p.\n", (void*)Address);
772 
773             for (i = 0; i < (sizeof(BreakPointHandles) / sizeof(BreakPointHandles[0])); i++)
774             {
775                 if (BreakPointHandles[i].Address == 0)
776                     HasFreeSlot = TRUE;
777             }
778 
779             if (!HasFreeSlot)
780             {
781                 /* We don't have a way to keep track of this break point. Fail. */
782                 KDDBGPRINT("No breakpoint slot available!\n");
783                 return LOOP_IF_SUCCESS(send_gdb_packet("E01"));
784             }
785 
786             State->ApiNumber = DbgKdWriteBreakPointApi;
787             State->u.WriteBreakPoint.BreakPointAddress = Address;
788             /* FIXME : ignoring all other Z0 arguments */
789 
790             /* KD will reply with KdSendPacket. Catch it */
791             KdpSendPacketHandler = WriteBreakPointSendHandler;
792             return KdPacketReceived;
793         }
794     }
795 
796     KDDBGPRINT("Unhandled 'Z' packet: %s\n", gdb_input);
797     return LOOP_IF_SUCCESS(send_gdb_packet("E01"));
798 }
799 
800 static
801 BOOLEAN
802 RestoreBreakPointSendHandler(
803     _In_ ULONG PacketType,
804     _In_ PSTRING MessageHeader,
805     _In_ PSTRING MessageData)
806 {
807     DBGKD_MANIPULATE_STATE64* State = (DBGKD_MANIPULATE_STATE64*)MessageHeader->Buffer;
808     ULONG i;
809 
810     if (PacketType != PACKET_TYPE_KD_STATE_MANIPULATE)
811     {
812         // KdAssert
813         KDDBGPRINT("Wrong packet type (%lu) received after DbgKdRestoreBreakPointApi request.\n", PacketType);
814         return FALSE;
815     }
816 
817     if (State->ApiNumber != DbgKdRestoreBreakPointApi)
818     {
819         KDDBGPRINT("Wrong API number (%lu) after DbgKdRestoreBreakPointApi request.\n", State->ApiNumber);
820         return FALSE;
821     }
822 
823     /* We ignore failure here. If DbgKdRestoreBreakPointApi fails,
824      * this means that the breakpoint was already invalid for KD. So clean it up on our side. */
825     for (i = 0; i < (sizeof(BreakPointHandles) / sizeof(BreakPointHandles[0])); i++)
826     {
827         if (BreakPointHandles[i].Handle == State->u.RestoreBreakPoint.BreakPointHandle)
828         {
829             BreakPointHandles[i].Address = 0;
830             BreakPointHandles[i].Handle = 0;
831             break;
832         }
833     }
834 
835     send_gdb_packet("OK");
836 
837     KdpSendPacketHandler = NULL;
838     KdpManipulateStateHandler = NULL;
839     return TRUE;
840 }
841 
842 static
843 KDSTATUS
844 handle_gdb_remove_breakpoint(
845     _Out_ DBGKD_MANIPULATE_STATE64* State,
846     _Out_ PSTRING MessageData,
847     _Out_ PULONG MessageLength,
848     _Inout_ PKD_CONTEXT KdContext)
849 {
850     State->ReturnStatus = STATUS_SUCCESS; /* ? */
851     State->Processor = CurrentStateChange.Processor;
852     State->ProcessorLevel = CurrentStateChange.ProcessorLevel;
853     if (MessageData)
854         MessageData->Length = 0;
855     *MessageLength = 0;
856 
857     switch (gdb_input[1])
858     {
859         case '0':
860         {
861             ULONG_PTR Address = hex_to_address(&gdb_input[3]);
862             ULONG i, Handle = 0;
863 
864             KDDBGPRINT("Removing breakpoint on %p.\n", (void*)Address);
865 
866             for (i = 0; i < (sizeof(BreakPointHandles) / sizeof(BreakPointHandles[0])); i++)
867             {
868                 if (BreakPointHandles[i].Address == Address)
869                 {
870                     Handle = BreakPointHandles[i].Handle;
871                     break;
872                 }
873             }
874 
875             if (Handle == 0)
876             {
877                 KDDBGPRINT("Received %s, but breakpoint was never inserted ?!\n", gdb_input);
878                 return LOOP_IF_SUCCESS(send_gdb_packet("E01"));
879             }
880 
881             State->ApiNumber = DbgKdRestoreBreakPointApi;
882             State->u.RestoreBreakPoint.BreakPointHandle = Handle;
883             /* FIXME : ignoring all other z0 arguments */
884 
885             /* KD will reply with KdSendPacket. Catch it */
886             KdpSendPacketHandler = RestoreBreakPointSendHandler;
887             return KdPacketReceived;
888         }
889     }
890 
891     KDDBGPRINT("Unhandled 'Z' packet: %s\n", gdb_input);
892     return LOOP_IF_SUCCESS(send_gdb_packet("E01"));
893 }
894 
895 static
896 KDSTATUS
897 handle_gdb_c(
898     _Out_ DBGKD_MANIPULATE_STATE64* State,
899     _Out_ PSTRING MessageData,
900     _Out_ PULONG MessageLength,
901     _Inout_ PKD_CONTEXT KdContext)
902 {
903     KDSTATUS Status;
904 
905     /* Tell GDB everything is fine, we will handle it */
906     Status = send_gdb_packet("OK");
907     if (Status != KdPacketReceived)
908         return Status;
909 
910 
911     if (CurrentStateChange.NewState == DbgKdExceptionStateChange)
912     {
913         DBGKM_EXCEPTION64* Exception = &CurrentStateChange.u.Exception;
914         ULONG_PTR ProgramCounter = KdpGetContextPc(&CurrentContext);
915 
916         /* See if we should update the program counter */
917         if (Exception && (Exception->ExceptionRecord.ExceptionCode == STATUS_BREAKPOINT)
918                 && ((*(KD_BREAKPOINT_TYPE*)ProgramCounter) == KD_BREAKPOINT_VALUE))
919         {
920             /* We must get past the breakpoint instruction */
921             KdpSetContextPc(&CurrentContext, ProgramCounter + KD_BREAKPOINT_SIZE);
922 
923             SetContextManipulateHandler(State, MessageData, MessageLength, KdContext);
924             KdpManipulateStateHandler = ContinueManipulateStateHandler;
925             return KdPacketReceived;
926         }
927     }
928 
929     return ContinueManipulateStateHandler(State, MessageData, MessageLength, KdContext);
930 }
931 
932 static
933 KDSTATUS
934 handle_gdb_C(
935     _Out_ DBGKD_MANIPULATE_STATE64* State,
936     _Out_ PSTRING MessageData,
937     _Out_ PULONG MessageLength,
938     _Inout_ PKD_CONTEXT KdContext)
939 {
940     KDSTATUS Status;
941 
942     /* Tell GDB everything is fine, we will handle it */
943     Status = send_gdb_packet("OK");
944     if (Status != KdPacketReceived)
945         return Status;
946 
947     if (CurrentStateChange.NewState == DbgKdExceptionStateChange)
948     {
949         /* Debugger didn't handle the exception, report it back to the kernel */
950         State->u.Continue2.ContinueStatus = CurrentStateChange.u.Exception.ExceptionRecord.ExceptionCode;
951         State->ApiNumber = DbgKdContinueApi2;
952         return KdPacketReceived;
953     }
954     /* We should never reach this ? */
955     return ContinueManipulateStateHandler(State, MessageData, MessageLength, KdContext);
956 }
957 
958 static
959 KDSTATUS
960 handle_gdb_s(
961     _Out_ DBGKD_MANIPULATE_STATE64* State,
962     _Out_ PSTRING MessageData,
963     _Out_ PULONG MessageLength,
964     _Inout_ PKD_CONTEXT KdContext)
965 {
966     KDDBGPRINT("Single stepping.\n");
967     /* Set CPU single step mode and continue */
968     KdpSetSingleStep(&CurrentContext);
969     SetContextManipulateHandler(State, MessageData, MessageLength, KdContext);
970     KdpManipulateStateHandler = ContinueManipulateStateHandler;
971     return KdPacketReceived;
972 }
973 
974 static
975 KDSTATUS
976 handle_gdb_v(
977     _Out_ DBGKD_MANIPULATE_STATE64* State,
978     _Out_ PSTRING MessageData,
979     _Out_ PULONG MessageLength,
980     _Inout_ PKD_CONTEXT KdContext)
981 {
982     if (strncmp(gdb_input, "vCont", 5) == 0)
983     {
984         if (gdb_input[5] == '?')
985         {
986             /* Report what we support */
987             return LOOP_IF_SUCCESS(send_gdb_packet("vCont;c;s"));
988         }
989 
990         if (strncmp(gdb_input, "vCont;c", 7) == 0)
991         {
992             return handle_gdb_c(State, MessageData, MessageLength, KdContext);
993         }
994 
995         if (strncmp(gdb_input, "vCont;s", 7) == 0)
996         {
997 
998             return handle_gdb_s(State, MessageData, MessageLength, KdContext);
999         }
1000     }
1001 
1002     KDDBGPRINT("Unhandled 'v' packet: %s\n", gdb_input);
1003     return LOOP_IF_SUCCESS(send_gdb_packet(""));
1004 }
1005 
1006 KDSTATUS
1007 gdb_receive_and_interpret_packet(
1008     _Out_ DBGKD_MANIPULATE_STATE64* State,
1009     _Out_ PSTRING MessageData,
1010     _Out_ PULONG MessageLength,
1011     _Inout_ PKD_CONTEXT KdContext)
1012 {
1013     KDSTATUS Status;
1014 
1015     do
1016     {
1017         KDDBGPRINT("KDGBD: Receiving packet.\n");
1018         Status = gdb_receive_packet(KdContext);
1019         KDDBGPRINT("KDGBD: Packet \"%s\" received with status %u\n", gdb_input, Status);
1020 
1021         if (Status != KdPacketReceived)
1022             return Status;
1023 
1024         Status = (KDSTATUS)-1;
1025 
1026         switch (gdb_input[0])
1027         {
1028         case '?':
1029             /* Send the Status */
1030             Status = LOOP_IF_SUCCESS(gdb_send_exception());
1031             break;
1032         case '!':
1033             Status = LOOP_IF_SUCCESS(send_gdb_packet("OK"));
1034             break;
1035         case 'c':
1036             Status = handle_gdb_c(State, MessageData, MessageLength, KdContext);
1037             break;
1038         case 'C':
1039             Status = handle_gdb_C(State, MessageData, MessageLength, KdContext);
1040             break;
1041         case 'g':
1042             Status = LOOP_IF_SUCCESS(gdb_send_registers());
1043             break;
1044         case 'H':
1045             Status = LOOP_IF_SUCCESS(handle_gdb_set_thread());
1046             break;
1047         case 'm':
1048             Status = handle_gdb_read_mem(State, MessageData, MessageLength, KdContext);
1049             break;
1050         case 'p':
1051             Status = LOOP_IF_SUCCESS(gdb_send_register());
1052             break;
1053         case 'q':
1054             Status = LOOP_IF_SUCCESS(handle_gdb_query());
1055             break;
1056         case 's':
1057             Status = handle_gdb_s(State, MessageData, MessageLength, KdContext);
1058             break;
1059         case 'T':
1060             Status = LOOP_IF_SUCCESS(handle_gdb_thread_alive());
1061             break;
1062         case 'v':
1063             Status = handle_gdb_v(State, MessageData, MessageLength, KdContext);
1064             break;
1065         case 'X':
1066             Status = handle_gdb_write_mem(State, MessageData, MessageLength, KdContext);
1067             break;
1068         case 'z':
1069             Status = handle_gdb_remove_breakpoint(State, MessageData, MessageLength, KdContext);
1070             break;
1071         case 'Z':
1072             Status = handle_gdb_insert_breakpoint(State, MessageData, MessageLength, KdContext);
1073             break;
1074         default:
1075             /* We don't know how to handle this request. */
1076             KDDBGPRINT("Unsupported GDB command: %s.\n", gdb_input);
1077             Status = LOOP_IF_SUCCESS(send_gdb_packet(""));
1078         }
1079     } while (Status == (KDSTATUS)-1);
1080 
1081     return Status;
1082 }
1083 
1084