[BLUE] Perform size/rectangle boundary checks on read/write operations. CORE-15108
[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 char* ptr;
372
373 /* Convert names to lower case. Yes this _is_ ugly */
374 _snprintf(name_helper, 64, "%wZ", &TableEntry->BaseDllName);
375 for (ptr = name_helper; *ptr; ptr++)
376 {
377 if (*ptr >= 'A' && *ptr <= 'Z')
378 *ptr += 'a' - 'A';
379 }
380
381 /* GDB doesn't load the file if you don't prefix it with a drive letter... */
382 mem_length = _snprintf(str_helper, 256, "<library name=\"C:\\%s\"><segment address=\"0x%p\"/></library>", &name_helper, DllBase);
383
384 /* DLL name must be too long. */
385 if (mem_length < 0)
386 {
387 KDDBGPRINT("Failed to report %wZ\n", &TableEntry->BaseDllName);
388 continue;
389 }
390
391 if ((Sent + mem_length) > ToSend)
392 {
393 /* We're done for this pass */
394 return finish_gdb_packet();
395 }
396
397 Sent += send_gdb_partial_binary(str_helper, mem_length);
398 }
399
400 if ((ToSend - Sent) > 15)
401 {
402 Sent += send_gdb_partial_binary("</library-list>", 15);
403 allDone = TRUE;
404 }
405
406 return finish_gdb_packet();
407
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_s(
908 _Out_ DBGKD_MANIPULATE_STATE64* State,
909 _Out_ PSTRING MessageData,
910 _Out_ PULONG MessageLength,
911 _Inout_ PKD_CONTEXT KdContext)
912 {
913 KDDBGPRINT("Single stepping.\n");
914 /* Set CPU single step mode and continue */
915 KdpSetSingleStep(&CurrentContext);
916 SetContextManipulateHandler(State, MessageData, MessageLength, KdContext);
917 KdpManipulateStateHandler = ContinueManipulateStateHandler;
918 return KdPacketReceived;
919 }
920
921 static
922 KDSTATUS
923 handle_gdb_v(
924 _Out_ DBGKD_MANIPULATE_STATE64* State,
925 _Out_ PSTRING MessageData,
926 _Out_ PULONG MessageLength,
927 _Inout_ PKD_CONTEXT KdContext)
928 {
929 if (strncmp(gdb_input, "vCont", 5) == 0)
930 {
931 if (gdb_input[5] == '?')
932 {
933 /* Report what we support */
934 return LOOP_IF_SUCCESS(send_gdb_packet("vCont;c;s"));
935 }
936
937 if (strncmp(gdb_input, "vCont;c", 7) == 0)
938 {
939 return handle_gdb_c(State, MessageData, MessageLength, KdContext);
940 }
941
942 if (strncmp(gdb_input, "vCont;s", 7) == 0)
943 {
944
945 return handle_gdb_s(State, MessageData, MessageLength, KdContext);
946 }
947 }
948
949 KDDBGPRINT("Unhandled 'v' packet: %s\n", gdb_input);
950 return LOOP_IF_SUCCESS(send_gdb_packet(""));
951 }
952
953 KDSTATUS
954 gdb_receive_and_interpret_packet(
955 _Out_ DBGKD_MANIPULATE_STATE64* State,
956 _Out_ PSTRING MessageData,
957 _Out_ PULONG MessageLength,
958 _Inout_ PKD_CONTEXT KdContext)
959 {
960 KDSTATUS Status;
961
962 do
963 {
964 KDDBGPRINT("KDGBD: Receiving packet.\n");
965 Status = gdb_receive_packet(KdContext);
966 KDDBGPRINT("KDGBD: Packet \"%s\" received with status %u\n", gdb_input, Status);
967
968 if (Status != KdPacketReceived)
969 return Status;
970
971 Status = (KDSTATUS)-1;
972
973 switch (gdb_input[0])
974 {
975 case '?':
976 /* Send the Status */
977 Status = LOOP_IF_SUCCESS(gdb_send_exception());
978 break;
979 case '!':
980 Status = LOOP_IF_SUCCESS(send_gdb_packet("OK"));
981 break;
982 case 'c':
983 Status = handle_gdb_c(State, MessageData, MessageLength, KdContext);
984 break;
985 case 'g':
986 Status = LOOP_IF_SUCCESS(gdb_send_registers());
987 break;
988 case 'H':
989 Status = LOOP_IF_SUCCESS(handle_gdb_set_thread());
990 break;
991 case 'm':
992 Status = handle_gdb_read_mem(State, MessageData, MessageLength, KdContext);
993 break;
994 case 'p':
995 Status = LOOP_IF_SUCCESS(gdb_send_register());
996 break;
997 case 'q':
998 Status = LOOP_IF_SUCCESS(handle_gdb_query());
999 break;
1000 case 's':
1001 Status = handle_gdb_s(State, MessageData, MessageLength, KdContext);
1002 break;
1003 case 'T':
1004 Status = LOOP_IF_SUCCESS(handle_gdb_thread_alive());
1005 break;
1006 case 'v':
1007 Status = handle_gdb_v(State, MessageData, MessageLength, KdContext);
1008 break;
1009 case 'X':
1010 Status = handle_gdb_write_mem(State, MessageData, MessageLength, KdContext);
1011 break;
1012 case 'z':
1013 Status = handle_gdb_remove_breakpoint(State, MessageData, MessageLength, KdContext);
1014 break;
1015 case 'Z':
1016 Status = handle_gdb_insert_breakpoint(State, MessageData, MessageLength, KdContext);
1017 break;
1018 default:
1019 /* We don't know how to handle this request. */
1020 KDDBGPRINT("Unsupported GDB command: %s.\n", gdb_input);
1021 Status = LOOP_IF_SUCCESS(send_gdb_packet(""));
1022 }
1023 } while (Status == (KDSTATUS)-1);
1024
1025 return Status;
1026 }
1027