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
LOOP_IF_SUCCESS(int x)25 LOOP_IF_SUCCESS(int x)
26 {
27 return (x == KdPacketReceived) ? (KDSTATUS)-1 : x;
28 }
29
30 /* PRIVATE FUNCTIONS **********************************************************/
31 static
32 UINT_PTR
hex_to_tid(char * buffer)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
hex_to_address(char * buffer)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
handle_gdb_set_thread(void)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
handle_gdb_thread_alive(void)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
handle_gdb_query(void)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
ReadMemorySendHandler(_In_ ULONG PacketType,_In_ PSTRING MessageHeader,_In_ PSTRING MessageData)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
handle_gdb_read_mem(_Out_ DBGKD_MANIPULATE_STATE64 * State,_Out_ PSTRING MessageData,_Out_ PULONG MessageLength,_Inout_ PKD_CONTEXT KdContext)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
WriteMemorySendHandler(_In_ ULONG PacketType,_In_ PSTRING MessageHeader,_In_ PSTRING MessageData)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
handle_gdb_write_mem(_Out_ DBGKD_MANIPULATE_STATE64 * State,_Out_ PSTRING MessageData,_Out_ PULONG MessageLength,_Inout_ PKD_CONTEXT KdContext)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
WriteBreakPointSendHandler(_In_ ULONG PacketType,_In_ PSTRING MessageHeader,_In_ PSTRING MessageData)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
handle_gdb_insert_breakpoint(_Out_ DBGKD_MANIPULATE_STATE64 * State,_Out_ PSTRING MessageData,_Out_ PULONG MessageLength,_Inout_ PKD_CONTEXT KdContext)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
RestoreBreakPointSendHandler(_In_ ULONG PacketType,_In_ PSTRING MessageHeader,_In_ PSTRING MessageData)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
handle_gdb_remove_breakpoint(_Out_ DBGKD_MANIPULATE_STATE64 * State,_Out_ PSTRING MessageData,_Out_ PULONG MessageLength,_Inout_ PKD_CONTEXT KdContext)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
handle_gdb_c(_Out_ DBGKD_MANIPULATE_STATE64 * State,_Out_ PSTRING MessageData,_Out_ PULONG MessageLength,_Inout_ PKD_CONTEXT KdContext)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->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 #if defined(_M_IX86) || defined(_M_AMD64)
928 if ((Exception->ExceptionRecord.ExceptionCode == STATUS_ASSERTION_FAILURE)
929 && ((*(KD_BREAKPOINT_TYPE*)ProgramCounter) == 0xCD)
930 && (*((KD_BREAKPOINT_TYPE*)ProgramCounter + 1) == 0x2C))
931 {
932 /* INT 2C (a.k.a. runtime check failure) */
933 KdpSetContextPc(&CurrentContext, ProgramCounter + 2);
934
935 SetContextManipulateHandler(State, MessageData, MessageLength, KdContext);
936 KdpManipulateStateHandler = ContinueManipulateStateHandler;
937 return KdPacketReceived;
938 }
939 #endif
940 }
941
942 return ContinueManipulateStateHandler(State, MessageData, MessageLength, KdContext);
943 }
944
945 static
946 KDSTATUS
handle_gdb_s(_Out_ DBGKD_MANIPULATE_STATE64 * State,_Out_ PSTRING MessageData,_Out_ PULONG MessageLength,_Inout_ PKD_CONTEXT KdContext)947 handle_gdb_s(
948 _Out_ DBGKD_MANIPULATE_STATE64* State,
949 _Out_ PSTRING MessageData,
950 _Out_ PULONG MessageLength,
951 _Inout_ PKD_CONTEXT KdContext)
952 {
953 KDDBGPRINT("Single stepping.\n");
954 /* Set CPU single step mode and continue */
955 KdpSetSingleStep(&CurrentContext);
956 SetContextManipulateHandler(State, MessageData, MessageLength, KdContext);
957 KdpManipulateStateHandler = ContinueManipulateStateHandler;
958 return KdPacketReceived;
959 }
960
961 static
962 KDSTATUS
handle_gdb_v(_Out_ DBGKD_MANIPULATE_STATE64 * State,_Out_ PSTRING MessageData,_Out_ PULONG MessageLength,_Inout_ PKD_CONTEXT KdContext)963 handle_gdb_v(
964 _Out_ DBGKD_MANIPULATE_STATE64* State,
965 _Out_ PSTRING MessageData,
966 _Out_ PULONG MessageLength,
967 _Inout_ PKD_CONTEXT KdContext)
968 {
969 if (strncmp(gdb_input, "vCont", 5) == 0)
970 {
971 if (gdb_input[5] == '?')
972 {
973 /* Report what we support */
974 return LOOP_IF_SUCCESS(send_gdb_packet("vCont;c;s"));
975 }
976
977 if (strncmp(gdb_input, "vCont;c", 7) == 0)
978 {
979 return handle_gdb_c(State, MessageData, MessageLength, KdContext);
980 }
981
982 if (strncmp(gdb_input, "vCont;s", 7) == 0)
983 {
984
985 return handle_gdb_s(State, MessageData, MessageLength, KdContext);
986 }
987 }
988
989 KDDBGPRINT("Unhandled 'v' packet: %s\n", gdb_input);
990 return LOOP_IF_SUCCESS(send_gdb_packet(""));
991 }
992
993 KDSTATUS
gdb_receive_and_interpret_packet(_Out_ DBGKD_MANIPULATE_STATE64 * State,_Out_ PSTRING MessageData,_Out_ PULONG MessageLength,_Inout_ PKD_CONTEXT KdContext)994 gdb_receive_and_interpret_packet(
995 _Out_ DBGKD_MANIPULATE_STATE64* State,
996 _Out_ PSTRING MessageData,
997 _Out_ PULONG MessageLength,
998 _Inout_ PKD_CONTEXT KdContext)
999 {
1000 KDSTATUS Status;
1001
1002 do
1003 {
1004 KDDBGPRINT("KDGBD: Receiving packet.\n");
1005 Status = gdb_receive_packet(KdContext);
1006 KDDBGPRINT("KDGBD: Packet \"%s\" received with status %u\n", gdb_input, Status);
1007
1008 if (Status != KdPacketReceived)
1009 return Status;
1010
1011 Status = (KDSTATUS)-1;
1012
1013 switch (gdb_input[0])
1014 {
1015 case '?':
1016 /* Send the Status */
1017 Status = LOOP_IF_SUCCESS(gdb_send_exception());
1018 break;
1019 case '!':
1020 Status = LOOP_IF_SUCCESS(send_gdb_packet("OK"));
1021 break;
1022 case 'c':
1023 case 'C':
1024 Status = handle_gdb_c(State, MessageData, MessageLength, KdContext);
1025 break;
1026 case 'g':
1027 Status = LOOP_IF_SUCCESS(gdb_send_registers());
1028 break;
1029 case 'H':
1030 Status = LOOP_IF_SUCCESS(handle_gdb_set_thread());
1031 break;
1032 case 'm':
1033 Status = handle_gdb_read_mem(State, MessageData, MessageLength, KdContext);
1034 break;
1035 case 'p':
1036 Status = LOOP_IF_SUCCESS(gdb_send_register());
1037 break;
1038 case 'q':
1039 Status = LOOP_IF_SUCCESS(handle_gdb_query());
1040 break;
1041 case 's':
1042 Status = handle_gdb_s(State, MessageData, MessageLength, KdContext);
1043 break;
1044 case 'T':
1045 Status = LOOP_IF_SUCCESS(handle_gdb_thread_alive());
1046 break;
1047 case 'v':
1048 Status = handle_gdb_v(State, MessageData, MessageLength, KdContext);
1049 break;
1050 case 'X':
1051 Status = handle_gdb_write_mem(State, MessageData, MessageLength, KdContext);
1052 break;
1053 case 'z':
1054 Status = handle_gdb_remove_breakpoint(State, MessageData, MessageLength, KdContext);
1055 break;
1056 case 'Z':
1057 Status = handle_gdb_insert_breakpoint(State, MessageData, MessageLength, KdContext);
1058 break;
1059 default:
1060 /* We don't know how to handle this request. */
1061 KDDBGPRINT("Unsupported GDB command: %s.\n", gdb_input);
1062 Status = LOOP_IF_SUCCESS(send_gdb_packet(""));
1063 }
1064 } while (Status == (KDSTATUS)-1);
1065
1066 return Status;
1067 }
1068
1069