xref: /reactos/drivers/base/kdgdb/gdb_input.c (revision a1fc312a)
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, "qThreadExtraInfo,", 17) == 0)
263     {
264         ULONG_PTR Pid, Tid;
265         PETHREAD Thread;
266         PEPROCESS Process;
267         char out_string[64];
268         STRING String = {0, 64, out_string};
269 
270         KDDBGPRINT("Giving extra info for");
271 
272 #if MONOPROCESS
273         Pid = 0;
274         Tid = hex_to_tid(&gdb_input[17]);
275 
276         KDDBGPRINT(" %p.\n", Tid);
277 
278         Thread = find_thread(Pid, Tid);
279         Process = CONTAINING_RECORD(Thread->Tcb.Process, EPROCESS, Pcb);
280 #else
281         Pid = hex_to_pid(&gdb_input[18]);
282         Tid = hex_to_tid(strstr(&gdb_input[18], ".") + 1);
283 
284         /* We cannot use PsLookupProcessThreadByCid as we could be running at any IRQL.
285          * So loop. */
286         KDDBGPRINT(" p%p.%p.\n", Pid, Tid);
287 
288         Process = find_process(Pid);
289         Thread = find_thread(Pid, Tid);
290 #endif
291 
292         if (PsGetThreadProcessId(Thread) == 0)
293         {
294             String.Length = sprintf(out_string, "SYSTEM");
295         }
296         else
297         {
298             String.Length = sprintf(out_string, "%.*s", 16, Process->ImageFileName);
299         }
300 
301         return gdb_send_debug_io(&String, FALSE);
302     }
303 
304     if (strcmp(gdb_input, "qTStatus") == 0)
305     {
306         /* No tracepoint support */
307         return send_gdb_packet("T0");
308     }
309 
310     if (strcmp(gdb_input, "qSymbol::") == 0)
311     {
312         /* No need */
313         return send_gdb_packet("OK");
314     }
315 
316     if (strncmp(gdb_input, "qXfer:libraries:read::", 22) == 0)
317     {
318         static LIST_ENTRY* CurrentEntry = NULL;
319         char str_helper[256];
320         char name_helper[64];
321         ULONG_PTR Offset = hex_to_address(&gdb_input[22]);
322         ULONG_PTR ToSend = hex_to_address(strstr(&gdb_input[22], ",") + 1);
323         ULONG Sent = 0;
324         static BOOLEAN allDone = FALSE;
325 
326         KDDBGPRINT("KDGDB: qXfer:libraries:read !\n");
327 
328         /* Start the packet */
329         start_gdb_packet();
330 
331         if (allDone)
332         {
333             send_gdb_partial_packet("l");
334             allDone = FALSE;
335             return finish_gdb_packet();
336         }
337 
338         send_gdb_partial_packet("m");
339         Sent++;
340 
341         /* Are we starting ? */
342         if (Offset == 0)
343         {
344             Sent += send_gdb_partial_binary("<?xml version=\"1.0\"?>", 21);
345             Sent += send_gdb_partial_binary("<library-list>", 14);
346 
347             CurrentEntry = ModuleListHead->Flink;
348 
349             if (!CurrentEntry)
350             {
351                 /* Ps is not initialized. Send end of XML data or mark that we are finished. */
352                 Sent += send_gdb_partial_binary("</library-list>", 15);
353                 allDone = TRUE;
354                 return finish_gdb_packet();
355             }
356         }
357 
358         for ( ;
359             CurrentEntry != ModuleListHead;
360             CurrentEntry = CurrentEntry->Flink)
361         {
362             PLDR_DATA_TABLE_ENTRY TableEntry = CONTAINING_RECORD(CurrentEntry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
363             PVOID DllBase = (PVOID)((ULONG_PTR)TableEntry->DllBase + 0x1000);
364             LONG mem_length;
365             USHORT i;
366 
367             /* Convert names to lower case. Yes this _is_ ugly */
368             for (i = 0; i < (TableEntry->BaseDllName.Length / sizeof(WCHAR)); i++)
369             {
370                 name_helper[i] = (char)TableEntry->BaseDllName.Buffer[i];
371                 if (name_helper[i] >= 'A' && name_helper[i] <= 'Z')
372                     name_helper[i] += 'a' - 'A';
373             }
374             name_helper[i] = 0;
375 
376             /* GDB doesn't load the file if you don't prefix it with a drive letter... */
377             mem_length = _snprintf(str_helper, 256, "<library name=\"C:\\%s\"><segment address=\"0x%p\"/></library>", &name_helper, DllBase);
378 
379             /* DLL name must be too long. */
380             if (mem_length < 0)
381             {
382                 KDDBGPRINT("Failed to report %wZ\n", &TableEntry->BaseDllName);
383                 continue;
384             }
385 
386             if ((Sent + mem_length) > ToSend)
387             {
388                 /* We're done for this pass */
389                 return finish_gdb_packet();
390             }
391 
392             Sent += send_gdb_partial_binary(str_helper, mem_length);
393         }
394 
395         if ((ToSend - Sent) > 15)
396         {
397             Sent += send_gdb_partial_binary("</library-list>", 15);
398             allDone = TRUE;
399         }
400 
401         return finish_gdb_packet();
402     }
403 
404     KDDBGPRINT("KDGDB: Unknown query: %s\n", gdb_input);
405     return send_gdb_packet("");
406 }
407 
408 #if 0
409 static
410 KDSTATUS
411 handle_gdb_registers(
412     _Out_ DBGKD_MANIPULATE_STATE64* State,
413     _Out_ PSTRING MessageData,
414     _Out_ PULONG MessageLength)
415 {
416     /*
417     if (gdb_dbg_thread)
418         KDDBGPRINT("Should get registers from other thread!\n");
419     */
420 
421     State->ApiNumber = DbgKdGetContextApi;
422     State->ReturnStatus = STATUS_SUCCESS; /* ? */
423     State->Processor = CurrentStateChange.Processor;
424     State->ProcessorLevel = CurrentStateChange.ProcessorLevel;
425     if (MessageData)
426         MessageData->Length = 0;
427     *MessageLength = 0;
428     return KdPacketReceived;
429 }
430 #endif
431 
432 static
433 BOOLEAN
434 ReadMemorySendHandler(
435     _In_ ULONG PacketType,
436     _In_ PSTRING MessageHeader,
437     _In_ PSTRING MessageData)
438 {
439     DBGKD_MANIPULATE_STATE64* State = (DBGKD_MANIPULATE_STATE64*)MessageHeader->Buffer;
440 
441     if (PacketType != PACKET_TYPE_KD_STATE_MANIPULATE)
442     {
443         // KdAssert
444         KDDBGPRINT("Wrong packet type (%lu) received after DbgKdReadVirtualMemoryApi request.\n", PacketType);
445         return FALSE;
446     }
447 
448     if (State->ApiNumber != DbgKdReadVirtualMemoryApi)
449     {
450         KDDBGPRINT("Wrong API number (%lu) after DbgKdReadVirtualMemoryApi request.\n", State->ApiNumber);
451         return FALSE;
452     }
453 
454     /* Check status. Allow to send partial data. */
455     if (!MessageData->Length && !NT_SUCCESS(State->ReturnStatus))
456         send_gdb_ntstatus(State->ReturnStatus);
457     else
458         send_gdb_memory(MessageData->Buffer, MessageData->Length);
459     KdpSendPacketHandler = NULL;
460     KdpManipulateStateHandler = NULL;
461 
462 #if MONOPROCESS
463     if (gdb_dbg_tid != 0)
464     /* Reset the TLB */
465 #else
466     if ((gdb_dbg_pid != 0) && gdb_pid_to_handle(gdb_dbg_pid) != PsGetCurrentProcessId())
467 #endif
468     {
469         /* Only do this if Ps is initialized */
470         if (ProcessListHead->Flink)
471             __writecr3(PsGetCurrentProcess()->Pcb.DirectoryTableBase[0]);
472     }
473 
474     return TRUE;
475 }
476 
477 static
478 KDSTATUS
479 handle_gdb_read_mem(
480     _Out_ DBGKD_MANIPULATE_STATE64* State,
481     _Out_ PSTRING MessageData,
482     _Out_ PULONG MessageLength,
483     _Inout_ PKD_CONTEXT KdContext)
484 {
485     State->ApiNumber = DbgKdReadVirtualMemoryApi;
486     State->ReturnStatus = STATUS_SUCCESS; /* ? */
487     State->Processor = CurrentStateChange.Processor;
488     State->ProcessorLevel = CurrentStateChange.ProcessorLevel;
489     if (MessageData)
490         MessageData->Length = 0;
491     *MessageLength = 0;
492 
493     /* Set the TLB according to the process being read. Pid 0 means any process. */
494 #if MONOPROCESS
495     if ((gdb_dbg_tid != 0) && gdb_tid_to_handle(gdb_dbg_tid) != PsGetCurrentThreadId())
496     {
497         PETHREAD AttachedThread = find_thread(0, gdb_dbg_tid);
498         PKPROCESS AttachedProcess;
499         if (AttachedThread == NULL)
500         {
501             KDDBGPRINT("The current GDB debug thread is invalid!");
502             return LOOP_IF_SUCCESS(send_gdb_packet("E03"));
503         }
504 
505         AttachedProcess = AttachedThread->Tcb.Process;
506         if (AttachedProcess == NULL)
507         {
508             KDDBGPRINT("The current GDB debug thread is invalid!");
509             return LOOP_IF_SUCCESS(send_gdb_packet("E03"));
510         }
511         __writecr3(AttachedProcess->DirectoryTableBase[0]);
512     }
513 #else
514     if ((gdb_dbg_pid != 0) && gdb_pid_to_handle(gdb_dbg_pid) != PsGetCurrentProcessId())
515     {
516         PEPROCESS AttachedProcess = find_process(gdb_dbg_pid);
517         if (AttachedProcess == NULL)
518         {
519             KDDBGPRINT("The current GDB debug thread is invalid!");
520             return LOOP_IF_SUCCESS(send_gdb_packet("E03"));
521         }
522         /* Only do this if Ps is initialized */
523         if (ProcessListHead->Flink)
524             __writecr3(AttachedProcess->Pcb.DirectoryTableBase[0]);
525     }
526 #endif
527 
528     State->u.ReadMemory.TargetBaseAddress = hex_to_address(&gdb_input[1]);
529     State->u.ReadMemory.TransferCount = hex_to_address(strstr(&gdb_input[1], ",") + 1);
530 
531     /* KD will reply with KdSendPacket. Catch it */
532     KdpSendPacketHandler = ReadMemorySendHandler;
533     return KdPacketReceived;
534 }
535 
536 static
537 BOOLEAN
538 WriteMemorySendHandler(
539     _In_ ULONG PacketType,
540     _In_ PSTRING MessageHeader,
541     _In_ PSTRING MessageData)
542 {
543     DBGKD_MANIPULATE_STATE64* State = (DBGKD_MANIPULATE_STATE64*)MessageHeader->Buffer;
544 
545     if (PacketType != PACKET_TYPE_KD_STATE_MANIPULATE)
546     {
547         // KdAssert
548         KDDBGPRINT("Wrong packet type (%lu) received after DbgKdWriteVirtualMemoryApi request.\n", PacketType);
549         return FALSE;
550     }
551 
552     if (State->ApiNumber != DbgKdWriteVirtualMemoryApi)
553     {
554         KDDBGPRINT("Wrong API number (%lu) after DbgKdWriteVirtualMemoryApi request.\n", State->ApiNumber);
555         return FALSE;
556     }
557 
558     /* Check status */
559     if (!NT_SUCCESS(State->ReturnStatus))
560         send_gdb_ntstatus(State->ReturnStatus);
561     else
562         send_gdb_packet("OK");
563     KdpSendPacketHandler = NULL;
564     KdpManipulateStateHandler = NULL;
565 
566 #if MONOPROCESS
567     if (gdb_dbg_tid != 0)
568     /* Reset the TLB */
569 #else
570     if ((gdb_dbg_pid != 0) && gdb_pid_to_handle(gdb_dbg_pid) != PsGetCurrentProcessId())
571 #endif
572     {
573         /* Only do this if Ps is initialized */
574         if (ProcessListHead->Flink)
575             __writecr3(PsGetCurrentProcess()->Pcb.DirectoryTableBase[0]);
576     }
577     return TRUE;
578 }
579 
580 static
581 KDSTATUS
582 handle_gdb_write_mem(
583     _Out_ DBGKD_MANIPULATE_STATE64* State,
584     _Out_ PSTRING MessageData,
585     _Out_ PULONG MessageLength,
586     _Inout_ PKD_CONTEXT KdContext)
587 {
588     /* Maximal input buffer is 0x1000. Each byte is encoded on two bytes by GDB */
589     static UCHAR OutBuffer[0x800];
590     ULONG BufferLength;
591     char* blob_ptr;
592     UCHAR* OutPtr;
593 
594     State->ApiNumber = DbgKdWriteVirtualMemoryApi;
595     State->ReturnStatus = STATUS_SUCCESS; /* ? */
596     State->Processor = CurrentStateChange.Processor;
597     State->ProcessorLevel = CurrentStateChange.ProcessorLevel;
598 
599     /* Set the TLB according to the process being read. Pid 0 means any process. */
600 #if MONOPROCESS
601     if ((gdb_dbg_tid != 0) && gdb_tid_to_handle(gdb_dbg_tid) != PsGetCurrentThreadId())
602     {
603         PETHREAD AttachedThread = find_thread(0, gdb_dbg_tid);
604         PKPROCESS AttachedProcess;
605         if (AttachedThread == NULL)
606         {
607             KDDBGPRINT("The current GDB debug thread is invalid!");
608             return LOOP_IF_SUCCESS(send_gdb_packet("E03"));
609         }
610 
611         AttachedProcess = AttachedThread->Tcb.Process;
612         if (AttachedProcess == NULL)
613         {
614             KDDBGPRINT("The current GDB debug thread is invalid!");
615             return LOOP_IF_SUCCESS(send_gdb_packet("E03"));
616         }
617         __writecr3(AttachedProcess->DirectoryTableBase[0]);
618     }
619 #else
620     if ((gdb_dbg_pid != 0) && gdb_pid_to_handle(gdb_dbg_pid) != PsGetCurrentProcessId())
621     {
622         PEPROCESS AttachedProcess = find_process(gdb_dbg_pid);
623         if (AttachedProcess == NULL)
624         {
625             KDDBGPRINT("The current GDB debug thread is invalid!");
626             return LOOP_IF_SUCCESS(send_gdb_packet("E03"));
627         }
628         /* Only do this if Ps is initialized */
629         if (ProcessListHead->Flink)
630             __writecr3(AttachedProcess->Pcb.DirectoryTableBase[0]);
631     }
632 #endif
633 
634     State->u.WriteMemory.TargetBaseAddress = hex_to_address(&gdb_input[1]);
635     BufferLength = hex_to_address(strstr(&gdb_input[1], ",") + 1);
636     if (BufferLength == 0)
637     {
638         /* Nothing to do */
639         return LOOP_IF_SUCCESS(send_gdb_packet("OK"));
640     }
641 
642     State->u.WriteMemory.TransferCount = BufferLength;
643     MessageData->Length = BufferLength;
644     MessageData->Buffer = (CHAR*)OutBuffer;
645 
646     OutPtr = OutBuffer;
647     blob_ptr = strstr(strstr(&gdb_input[1], ",") + 1, ":") + 1;
648     while (BufferLength)
649     {
650         if (BufferLength >= 4)
651         {
652             *((ULONG*)OutPtr) = *((ULONG*)blob_ptr);
653             OutPtr += 4;
654             blob_ptr += 4;
655             BufferLength -= 4;
656         }
657         else if (BufferLength >= 2)
658         {
659             *((USHORT*)OutPtr) = *((USHORT*)blob_ptr);
660             OutPtr += 2;
661             blob_ptr += 2;
662             BufferLength -= 2;
663         }
664         else
665         {
666             *OutPtr++ = *blob_ptr++;
667             BufferLength--;
668         }
669     }
670 
671     /* KD will reply with KdSendPacket. Catch it */
672     KdpSendPacketHandler = WriteMemorySendHandler;
673     return KdPacketReceived;
674 }
675 
676 static
677 BOOLEAN
678 WriteBreakPointSendHandler(
679     _In_ ULONG PacketType,
680     _In_ PSTRING MessageHeader,
681     _In_ PSTRING MessageData)
682 {
683     DBGKD_MANIPULATE_STATE64* State = (DBGKD_MANIPULATE_STATE64*)MessageHeader->Buffer;
684 
685     if (PacketType != PACKET_TYPE_KD_STATE_MANIPULATE)
686     {
687         // KdAssert
688         KDDBGPRINT("Wrong packet type (%lu) received after DbgKdWriteBreakPointApi request.\n", PacketType);
689         return FALSE;
690     }
691 
692     if (State->ApiNumber != DbgKdWriteBreakPointApi)
693     {
694         KDDBGPRINT("Wrong API number (%lu) after DbgKdWriteBreakPointApi request.\n", State->ApiNumber);
695         return FALSE;
696     }
697 
698     /* Check status */
699     if (!NT_SUCCESS(State->ReturnStatus))
700     {
701         KDDBGPRINT("Inserting breakpoint failed!\n");
702         send_gdb_ntstatus(State->ReturnStatus);
703     }
704     else
705     {
706         /* Keep track of the address+handle couple */
707         ULONG i;
708         for (i = 0; i < (sizeof(BreakPointHandles) / sizeof(BreakPointHandles[0])); i++)
709         {
710             if (BreakPointHandles[i].Address == 0)
711             {
712                 BreakPointHandles[i].Address = (ULONG_PTR)State->u.WriteBreakPoint.BreakPointAddress;
713                 BreakPointHandles[i].Handle = State->u.WriteBreakPoint.BreakPointHandle;
714                 break;
715             }
716         }
717         send_gdb_packet("OK");
718     }
719     KdpSendPacketHandler = NULL;
720     KdpManipulateStateHandler = NULL;
721     return TRUE;
722 }
723 
724 static
725 KDSTATUS
726 handle_gdb_insert_breakpoint(
727     _Out_ DBGKD_MANIPULATE_STATE64* State,
728     _Out_ PSTRING MessageData,
729     _Out_ PULONG MessageLength,
730     _Inout_ PKD_CONTEXT KdContext)
731 {
732     State->ReturnStatus = STATUS_SUCCESS; /* ? */
733     State->Processor = CurrentStateChange.Processor;
734     State->ProcessorLevel = CurrentStateChange.ProcessorLevel;
735     if (MessageData)
736         MessageData->Length = 0;
737     *MessageLength = 0;
738 
739     switch (gdb_input[1])
740     {
741         case '0':
742         {
743             ULONG_PTR Address = hex_to_address(&gdb_input[3]);
744             ULONG i;
745             BOOLEAN HasFreeSlot = FALSE;
746 
747             KDDBGPRINT("Inserting breakpoint at %p.\n", (void*)Address);
748 
749             for (i = 0; i < (sizeof(BreakPointHandles) / sizeof(BreakPointHandles[0])); i++)
750             {
751                 if (BreakPointHandles[i].Address == 0)
752                     HasFreeSlot = TRUE;
753             }
754 
755             if (!HasFreeSlot)
756             {
757                 /* We don't have a way to keep track of this break point. Fail. */
758                 KDDBGPRINT("No breakpoint slot available!\n");
759                 return LOOP_IF_SUCCESS(send_gdb_packet("E01"));
760             }
761 
762             State->ApiNumber = DbgKdWriteBreakPointApi;
763             State->u.WriteBreakPoint.BreakPointAddress = Address;
764             /* FIXME : ignoring all other Z0 arguments */
765 
766             /* KD will reply with KdSendPacket. Catch it */
767             KdpSendPacketHandler = WriteBreakPointSendHandler;
768             return KdPacketReceived;
769         }
770     }
771 
772     KDDBGPRINT("Unhandled 'Z' packet: %s\n", gdb_input);
773     return LOOP_IF_SUCCESS(send_gdb_packet("E01"));
774 }
775 
776 static
777 BOOLEAN
778 RestoreBreakPointSendHandler(
779     _In_ ULONG PacketType,
780     _In_ PSTRING MessageHeader,
781     _In_ PSTRING MessageData)
782 {
783     DBGKD_MANIPULATE_STATE64* State = (DBGKD_MANIPULATE_STATE64*)MessageHeader->Buffer;
784     ULONG i;
785 
786     if (PacketType != PACKET_TYPE_KD_STATE_MANIPULATE)
787     {
788         // KdAssert
789         KDDBGPRINT("Wrong packet type (%lu) received after DbgKdRestoreBreakPointApi request.\n", PacketType);
790         return FALSE;
791     }
792 
793     if (State->ApiNumber != DbgKdRestoreBreakPointApi)
794     {
795         KDDBGPRINT("Wrong API number (%lu) after DbgKdRestoreBreakPointApi request.\n", State->ApiNumber);
796         return FALSE;
797     }
798 
799     /* We ignore failure here. If DbgKdRestoreBreakPointApi fails,
800      * this means that the breakpoint was already invalid for KD. So clean it up on our side. */
801     for (i = 0; i < (sizeof(BreakPointHandles) / sizeof(BreakPointHandles[0])); i++)
802     {
803         if (BreakPointHandles[i].Handle == State->u.RestoreBreakPoint.BreakPointHandle)
804         {
805             BreakPointHandles[i].Address = 0;
806             BreakPointHandles[i].Handle = 0;
807             break;
808         }
809     }
810 
811     send_gdb_packet("OK");
812 
813     KdpSendPacketHandler = NULL;
814     KdpManipulateStateHandler = NULL;
815     return TRUE;
816 }
817 
818 static
819 KDSTATUS
820 handle_gdb_remove_breakpoint(
821     _Out_ DBGKD_MANIPULATE_STATE64* State,
822     _Out_ PSTRING MessageData,
823     _Out_ PULONG MessageLength,
824     _Inout_ PKD_CONTEXT KdContext)
825 {
826     State->ReturnStatus = STATUS_SUCCESS; /* ? */
827     State->Processor = CurrentStateChange.Processor;
828     State->ProcessorLevel = CurrentStateChange.ProcessorLevel;
829     if (MessageData)
830         MessageData->Length = 0;
831     *MessageLength = 0;
832 
833     switch (gdb_input[1])
834     {
835         case '0':
836         {
837             ULONG_PTR Address = hex_to_address(&gdb_input[3]);
838             ULONG i, Handle = 0;
839 
840             KDDBGPRINT("Removing breakpoint on %p.\n", (void*)Address);
841 
842             for (i = 0; i < (sizeof(BreakPointHandles) / sizeof(BreakPointHandles[0])); i++)
843             {
844                 if (BreakPointHandles[i].Address == Address)
845                 {
846                     Handle = BreakPointHandles[i].Handle;
847                     break;
848                 }
849             }
850 
851             if (Handle == 0)
852             {
853                 KDDBGPRINT("Received %s, but breakpoint was never inserted ?!\n", gdb_input);
854                 return LOOP_IF_SUCCESS(send_gdb_packet("E01"));
855             }
856 
857             State->ApiNumber = DbgKdRestoreBreakPointApi;
858             State->u.RestoreBreakPoint.BreakPointHandle = Handle;
859             /* FIXME : ignoring all other z0 arguments */
860 
861             /* KD will reply with KdSendPacket. Catch it */
862             KdpSendPacketHandler = RestoreBreakPointSendHandler;
863             return KdPacketReceived;
864         }
865     }
866 
867     KDDBGPRINT("Unhandled 'Z' packet: %s\n", gdb_input);
868     return LOOP_IF_SUCCESS(send_gdb_packet("E01"));
869 }
870 
871 static
872 KDSTATUS
873 handle_gdb_c(
874     _Out_ DBGKD_MANIPULATE_STATE64* State,
875     _Out_ PSTRING MessageData,
876     _Out_ PULONG MessageLength,
877     _Inout_ PKD_CONTEXT KdContext)
878 {
879     KDSTATUS Status;
880 
881     /* Tell GDB everything is fine, we will handle it */
882     Status = send_gdb_packet("OK");
883     if (Status != KdPacketReceived)
884         return Status;
885 
886 
887     if (CurrentStateChange.NewState == DbgKdExceptionStateChange)
888     {
889         DBGKM_EXCEPTION64* Exception = &CurrentStateChange.u.Exception;
890         ULONG_PTR ProgramCounter = KdpGetContextPc(&CurrentContext);
891 
892         /* See if we should update the program counter */
893         if (Exception && (Exception->ExceptionRecord.ExceptionCode == STATUS_BREAKPOINT)
894                 && ((*(KD_BREAKPOINT_TYPE*)ProgramCounter) == KD_BREAKPOINT_VALUE))
895         {
896             /* We must get past the breakpoint instruction */
897             KdpSetContextPc(&CurrentContext, ProgramCounter + KD_BREAKPOINT_SIZE);
898 
899             SetContextManipulateHandler(State, MessageData, MessageLength, KdContext);
900             KdpManipulateStateHandler = ContinueManipulateStateHandler;
901             return KdPacketReceived;
902         }
903     }
904 
905     return ContinueManipulateStateHandler(State, MessageData, MessageLength, KdContext);
906 }
907 
908 static
909 KDSTATUS
910 handle_gdb_C(
911     _Out_ DBGKD_MANIPULATE_STATE64* State,
912     _Out_ PSTRING MessageData,
913     _Out_ PULONG MessageLength,
914     _Inout_ PKD_CONTEXT KdContext)
915 {
916     KDSTATUS Status;
917 
918     /* Tell GDB everything is fine, we will handle it */
919     Status = send_gdb_packet("OK");
920     if (Status != KdPacketReceived)
921         return Status;
922 
923     if (CurrentStateChange.NewState == DbgKdExceptionStateChange)
924     {
925         /* Debugger didn't handle the exception, report it back to the kernel */
926         State->u.Continue2.ContinueStatus = CurrentStateChange.u.Exception.ExceptionRecord.ExceptionCode;
927         State->ApiNumber = DbgKdContinueApi2;
928         return KdPacketReceived;
929     }
930     /* We should never reach this ? */
931     return ContinueManipulateStateHandler(State, MessageData, MessageLength, KdContext);
932 }
933 
934 static
935 KDSTATUS
936 handle_gdb_s(
937     _Out_ DBGKD_MANIPULATE_STATE64* State,
938     _Out_ PSTRING MessageData,
939     _Out_ PULONG MessageLength,
940     _Inout_ PKD_CONTEXT KdContext)
941 {
942     KDDBGPRINT("Single stepping.\n");
943     /* Set CPU single step mode and continue */
944     KdpSetSingleStep(&CurrentContext);
945     SetContextManipulateHandler(State, MessageData, MessageLength, KdContext);
946     KdpManipulateStateHandler = ContinueManipulateStateHandler;
947     return KdPacketReceived;
948 }
949 
950 static
951 KDSTATUS
952 handle_gdb_v(
953     _Out_ DBGKD_MANIPULATE_STATE64* State,
954     _Out_ PSTRING MessageData,
955     _Out_ PULONG MessageLength,
956     _Inout_ PKD_CONTEXT KdContext)
957 {
958     if (strncmp(gdb_input, "vCont", 5) == 0)
959     {
960         if (gdb_input[5] == '?')
961         {
962             /* Report what we support */
963             return LOOP_IF_SUCCESS(send_gdb_packet("vCont;c;s"));
964         }
965 
966         if (strncmp(gdb_input, "vCont;c", 7) == 0)
967         {
968             return handle_gdb_c(State, MessageData, MessageLength, KdContext);
969         }
970 
971         if (strncmp(gdb_input, "vCont;s", 7) == 0)
972         {
973 
974             return handle_gdb_s(State, MessageData, MessageLength, KdContext);
975         }
976     }
977 
978     KDDBGPRINT("Unhandled 'v' packet: %s\n", gdb_input);
979     return LOOP_IF_SUCCESS(send_gdb_packet(""));
980 }
981 
982 KDSTATUS
983 gdb_receive_and_interpret_packet(
984     _Out_ DBGKD_MANIPULATE_STATE64* State,
985     _Out_ PSTRING MessageData,
986     _Out_ PULONG MessageLength,
987     _Inout_ PKD_CONTEXT KdContext)
988 {
989     KDSTATUS Status;
990 
991     do
992     {
993         KDDBGPRINT("KDGBD: Receiving packet.\n");
994         Status = gdb_receive_packet(KdContext);
995         KDDBGPRINT("KDGBD: Packet \"%s\" received with status %u\n", gdb_input, Status);
996 
997         if (Status != KdPacketReceived)
998             return Status;
999 
1000         Status = (KDSTATUS)-1;
1001 
1002         switch (gdb_input[0])
1003         {
1004         case '?':
1005             /* Send the Status */
1006             Status = LOOP_IF_SUCCESS(gdb_send_exception());
1007             break;
1008         case '!':
1009             Status = LOOP_IF_SUCCESS(send_gdb_packet("OK"));
1010             break;
1011         case 'c':
1012             Status = handle_gdb_c(State, MessageData, MessageLength, KdContext);
1013             break;
1014         case 'C':
1015             Status = handle_gdb_C(State, MessageData, MessageLength, KdContext);
1016             break;
1017         case 'g':
1018             Status = LOOP_IF_SUCCESS(gdb_send_registers());
1019             break;
1020         case 'H':
1021             Status = LOOP_IF_SUCCESS(handle_gdb_set_thread());
1022             break;
1023         case 'm':
1024             Status = handle_gdb_read_mem(State, MessageData, MessageLength, KdContext);
1025             break;
1026         case 'p':
1027             Status = LOOP_IF_SUCCESS(gdb_send_register());
1028             break;
1029         case 'q':
1030             Status = LOOP_IF_SUCCESS(handle_gdb_query());
1031             break;
1032         case 's':
1033             Status = handle_gdb_s(State, MessageData, MessageLength, KdContext);
1034             break;
1035         case 'T':
1036             Status = LOOP_IF_SUCCESS(handle_gdb_thread_alive());
1037             break;
1038         case 'v':
1039             Status = handle_gdb_v(State, MessageData, MessageLength, KdContext);
1040             break;
1041         case 'X':
1042             Status = handle_gdb_write_mem(State, MessageData, MessageLength, KdContext);
1043             break;
1044         case 'z':
1045             Status = handle_gdb_remove_breakpoint(State, MessageData, MessageLength, KdContext);
1046             break;
1047         case 'Z':
1048             Status = handle_gdb_insert_breakpoint(State, MessageData, MessageLength, KdContext);
1049             break;
1050         default:
1051             /* We don't know how to handle this request. */
1052             KDDBGPRINT("Unsupported GDB command: %s.\n", gdb_input);
1053             Status = LOOP_IF_SUCCESS(send_gdb_packet(""));
1054         }
1055     } while (Status == (KDSTATUS)-1);
1056 
1057     return Status;
1058 }
1059 
1060