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