[KDGDB] Allow kdgdb to continue when hit by a first-chance exception.
[reactos.git] / drivers / base / kdgdb / gdb_input.c
1 /*
2 * COPYRIGHT: GPL, see COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: drivers/base/kddll/gdb_input.c
5 * PURPOSE: Base functions for the kernel debugger.
6 */
7
8 #include "kdgdb.h"
9
10 /* LOCALS *********************************************************************/
11 static ULONG_PTR gdb_run_tid;
12 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(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