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.
12 /* LOCALS *********************************************************************/
13 static HANDLE gdb_run_thread
;
14 static HANDLE gdb_dbg_process
;
15 HANDLE gdb_dbg_thread
;
16 CONTEXT CurrentContext
;
18 /* PRIVATE FUNCTIONS **********************************************************/
21 hex_to_thread(char* buffer
)
27 hex
= hex_value(*buffer
++);
38 hex_to_address(char* buffer
)
44 hex
= hex_value(*buffer
++);
56 handle_gdb_set_thread(void)
61 if (strcmp(&gdb_input
[2], "-1") == 0)
62 gdb_run_thread
= (HANDLE
)-1;
64 gdb_run_thread
= hex_to_thread(&gdb_input
[2]);
65 send_gdb_packet("OK");
68 if (strncmp(&gdb_input
[2], "p-1", 3) == 0)
70 gdb_dbg_process
= (HANDLE
)-1;
71 gdb_dbg_thread
= (HANDLE
)-1;
75 char* ptr
= strstr(gdb_input
, ".") + 1;
76 gdb_dbg_process
= hex_to_thread(&gdb_input
[3]);
77 if (strncmp(ptr
, "-1", 2) == 0)
78 gdb_dbg_thread
= (HANDLE
)-1;
80 gdb_dbg_thread
= hex_to_thread(ptr
);
82 send_gdb_packet("OK");
85 KDDBGPRINT("KDGBD: Unknown 'H' command: %s\n", gdb_input
);
92 handle_gdb_thread_alive(void)
94 char* ptr
= strstr(gdb_input
, ".") + 1;
99 ClientId
.UniqueProcess
= hex_to_thread(&gdb_input
[2]);
100 ClientId
.UniqueThread
= hex_to_thread(ptr
);
102 Status
= PsLookupProcessThreadByCid(&ClientId
, NULL
, &Thread
);
104 if (!NT_SUCCESS(Status
))
106 /* Thread doesn't exist */
107 send_gdb_packet("E03");
112 ObDereferenceObject(Thread
);
113 send_gdb_packet("OK");
119 handle_gdb_query(_Inout_ PKD_CONTEXT KdContext
)
121 if (strncmp(gdb_input
, "qSupported:", 11) == 0)
123 send_gdb_packet("PacketSize=4096;multiprocess+;");
127 if (strncmp(gdb_input
, "qAttached", 9) == 0)
129 /* Say yes: the remote server didn't create the process, ReactOS did! */
130 send_gdb_packet("0");
134 if (strncmp(gdb_input
, "qRcmd,", 6) == 0)
136 send_gdb_packet("OK");
140 if (strcmp(gdb_input
, "qC") == 0)
143 sprintf(gdb_out
, "QC:p%p.%p;",
144 PsGetThreadProcessId((PETHREAD
)(ULONG_PTR
)CurrentStateChange
.Thread
),
145 PsGetThreadId((PETHREAD
)(ULONG_PTR
)CurrentStateChange
.Thread
));
146 send_gdb_packet(gdb_out
);
150 if (strncmp(gdb_input
, "qfThreadInfo", 12) == 0)
152 LIST_ENTRY
* ProcessListHead
= (LIST_ENTRY
*)KdDebuggerDataBlock
->PsActiveProcessHead
.Pointer
;
153 LIST_ENTRY
* ProcessEntry
;
156 KDDBGPRINT("ProcessListHead: %p.\n", ProcessListHead
);
158 /* Maybe this was not initialized yet */
159 if (!ProcessListHead
->Flink
)
162 /* Just tell GDB about the current thread */
163 sprintf(gdb_out
, "mp%p.%p", PsGetCurrentProcessId(), PsGetCurrentThreadId());
164 send_gdb_packet(gdb_out
);
165 gdb_receive_packet(KdContext
);
166 if (strncmp(gdb_input
, "qsThreadInfo", 12) != 0)
169 KDDBGPRINT("Received %s instead of qsThreadInfo!\n", gdb_input
);
172 send_gdb_packet("l");
176 /* List all processes */
177 for (ProcessEntry
= ProcessListHead
->Flink
;
178 ProcessEntry
!= ProcessListHead
;
179 ProcessEntry
= ProcessEntry
->Flink
)
181 BOOLEAN FirstThread
= TRUE
;
182 LIST_ENTRY
* ThreadEntry
;
184 static char gdb_out
[1024];
188 Process
= CONTAINING_RECORD(ProcessEntry
, EPROCESS
, ActiveProcessLinks
);
190 KDDBGPRINT("gdb_out %p.\n", gdb_out
);
193 /* List threads from this process */
194 for (ThreadEntry
= Process
->ThreadListHead
.Flink
;
195 ThreadEntry
!= &Process
->ThreadListHead
;
196 ThreadEntry
= ThreadEntry
->Flink
)
198 Thread
= CONTAINING_RECORD(ThreadEntry
, ETHREAD
, ThreadListEntry
);
200 KDDBGPRINT("ptr %p.\n", ptr
);
202 /* See if we should add a comma */
212 ptr
+= _snprintf(ptr
, 1024 - (ptr
- gdb_out
),
213 "p%p.%p", PsGetProcessId(Process
), PsGetThreadId(Thread
));
214 if (ptr
> (gdb_out
+ 1024))
216 /* send what we got */
217 KDDBGPRINT("Sending %s.\n", gdb_out
);
218 send_gdb_packet(gdb_out
);
219 gdb_receive_packet(KdContext
);
220 if (strncmp(gdb_input
, "qsThreadInfo", 12) != 0)
223 KDDBGPRINT("Received %s instead of qsThreadInfo!\n", gdb_input
);
233 /* send the list for this process */
234 KDDBGPRINT("Sending %s.\n", gdb_out
);
235 send_gdb_packet(gdb_out
);
236 gdb_receive_packet(KdContext
);
237 if (strncmp(gdb_input
, "qsThreadInfo", 12) != 0)
240 KDDBGPRINT("Received %s instead of qsThreadInfo!\n", gdb_input
);
245 /* We're done. Send end-of-list packet */
246 send_gdb_packet("l");
250 KDDBGPRINT("KDGDB: Unknown query: %s\n", gdb_input
);
257 handle_gdb_registers(
258 _Out_ DBGKD_MANIPULATE_STATE64
* State
,
259 _Out_ PSTRING MessageData
,
260 _Out_ PULONG MessageLength
)
264 KDDBGPRINT("Should get registers from other thread!\n");
267 State
->ApiNumber
= DbgKdGetContextApi
;
268 State
->ReturnStatus
= STATUS_SUCCESS
; /* ? */
269 State
->Processor
= CurrentStateChange
.Processor
;
270 State
->ProcessorLevel
= CurrentStateChange
.ProcessorLevel
;
272 MessageData
->Length
= 0;
274 return KdPacketReceived
;
280 ReadMemorySendHandler(
281 _In_ ULONG PacketType
,
282 _In_ PSTRING MessageHeader
,
283 _In_ PSTRING MessageData
)
285 DBGKD_MANIPULATE_STATE64
* State
= (DBGKD_MANIPULATE_STATE64
*)MessageHeader
->Buffer
;
287 if (PacketType
!= PACKET_TYPE_KD_STATE_MANIPULATE
)
290 KDDBGPRINT("Wrong packet type (%lu) received after DbgKdReadVirtualMemoryApi request.\n", PacketType
);
294 if (State
->ApiNumber
!= DbgKdReadVirtualMemoryApi
)
296 KDDBGPRINT("Wrong API number (%lu) after DbgKdReadVirtualMemoryApi request.\n", State
->ApiNumber
);
300 if (!NT_SUCCESS(State
->ReturnStatus
))
301 send_gdb_ntstatus(State
->ReturnStatus
);
303 send_gdb_memory(MessageData
->Buffer
, MessageData
->Length
);
304 KdpSendPacketHandler
= NULL
;
310 _Out_ DBGKD_MANIPULATE_STATE64
* State
,
311 _Out_ PSTRING MessageData
,
312 _Out_ PULONG MessageLength
)
314 State
->ApiNumber
= DbgKdReadVirtualMemoryApi
;
315 State
->ReturnStatus
= STATUS_SUCCESS
; /* ? */
316 State
->Processor
= CurrentStateChange
.Processor
;
317 State
->ProcessorLevel
= CurrentStateChange
.ProcessorLevel
;
319 MessageData
->Length
= 0;
322 State
->u
.ReadMemory
.TargetBaseAddress
= hex_to_address(&gdb_input
[1]);
323 State
->u
.ReadMemory
.TransferCount
= hex_to_address(strstr(&gdb_input
[1], ",") + 1);
325 /* KD will reply with KdSendPacket. Catch it */
326 KdpSendPacketHandler
= ReadMemorySendHandler
;
328 return KdPacketReceived
;
333 GetCurrentContextSendHandler(
334 _In_ ULONG PacketType
,
335 _In_ PSTRING MessageHeader
,
336 _In_ PSTRING MessageData
339 DBGKD_MANIPULATE_STATE64
* State
= (DBGKD_MANIPULATE_STATE64
*)MessageHeader
->Buffer
;
340 const CONTEXT
* Context
= (const CONTEXT
*)MessageData
->Buffer
;
342 if ((PacketType
!= PACKET_TYPE_KD_STATE_MANIPULATE
)
343 || (State
->ApiNumber
!= DbgKdGetContextApi
)
344 || (MessageData
->Length
< sizeof(*Context
)))
346 /* Should we bugcheck ? */
351 RtlCopyMemory(&CurrentContext
, Context
, sizeof(*Context
));
357 _Out_ DBGKD_MANIPULATE_STATE64
* State
,
358 _Out_ PSTRING MessageData
,
359 _Out_ PULONG MessageLength
,
360 _Inout_ PKD_CONTEXT KdContext
,
361 _In_opt_ KDP_MANIPULATESTATE_HANDLER ManipulateStateHandler
364 State
->ApiNumber
= DbgKdGetContextApi
;
365 State
->Processor
= CurrentStateChange
.Processor
;
366 State
->ReturnStatus
= STATUS_SUCCESS
;
367 State
->ProcessorLevel
= CurrentStateChange
.ProcessorLevel
;
368 MessageData
->Length
= 0;
370 /* Update the send <-> receive loop handler */
371 KdpSendPacketHandler
= GetCurrentContextSendHandler
;
372 KdpManipulateStateHandler
= ManipulateStateHandler
;
377 SetContextSendHandler(
378 _In_ ULONG PacketType
,
379 _In_ PSTRING MessageHeader
,
380 _In_ PSTRING MessageData
383 DBGKD_MANIPULATE_STATE64
* State
= (DBGKD_MANIPULATE_STATE64
*)MessageHeader
->Buffer
;
385 /* We just confirm that all went well */
386 if ((PacketType
!= PACKET_TYPE_KD_STATE_MANIPULATE
)
387 || (State
->ApiNumber
!= DbgKdSetContextApi
)
388 || (State
->ReturnStatus
!= STATUS_SUCCESS
))
390 /* Should we bugcheck ? */
398 _Out_ DBGKD_MANIPULATE_STATE64
* State
,
399 _Out_ PSTRING MessageData
,
400 _Out_ PULONG MessageLength
,
401 _Inout_ PKD_CONTEXT KdContext
,
402 _In_opt_ KDP_MANIPULATESTATE_HANDLER ManipulateStateHandler
405 State
->ApiNumber
= DbgKdSetContextApi
;
406 State
->Processor
= CurrentStateChange
.Processor
;
407 State
->ReturnStatus
= STATUS_SUCCESS
;
408 State
->ProcessorLevel
= CurrentStateChange
.ProcessorLevel
;
409 MessageData
->Length
= sizeof(CurrentContext
);
411 if (MessageData
->MaximumLength
< sizeof(CurrentContext
))
416 RtlCopyMemory(MessageData
->Buffer
, &CurrentContext
, sizeof(CurrentContext
));
418 /* Update the send <-> receive loop handlers */
419 KdpSendPacketHandler
= SetContextSendHandler
;
420 KdpManipulateStateHandler
= ManipulateStateHandler
;
422 return KdPacketReceived
;
428 _Out_ DBGKD_MANIPULATE_STATE64
* State
,
429 _Out_ PSTRING MessageData
,
430 _Out_ PULONG MessageLength
,
431 _Inout_ PKD_CONTEXT KdContext
435 State
->ApiNumber
= DbgKdContinueApi
;
436 State
->ReturnStatus
= STATUS_SUCCESS
; /* ? */
437 State
->Processor
= CurrentStateChange
.Processor
;
438 State
->ProcessorLevel
= CurrentStateChange
.ProcessorLevel
;
440 MessageData
->Length
= 0;
442 State
->u
.Continue
.ContinueStatus
= STATUS_SUCCESS
;
444 /* We definitely are at the end of the send <-> receive loop, if any */
445 KdpSendPacketHandler
= NULL
;
446 KdpManipulateStateHandler
= NULL
;
448 /* Tell GDB we are fine */
449 send_gdb_packet("OK");
450 return KdPacketReceived
;
455 UpdateProgramCounterSendContinue(
456 _Out_ DBGKD_MANIPULATE_STATE64
* State
,
457 _Out_ PSTRING MessageData
,
458 _Out_ PULONG MessageLength
,
459 _Inout_ PKD_CONTEXT KdContext
)
461 ULONG_PTR ProgramCounter
;
463 /* So we must get past the breakpoint instruction */
464 ProgramCounter
= KdpGetContextPc(&CurrentContext
);
465 KdpSetContextPc(&CurrentContext
, ProgramCounter
+ KD_BREAKPOINT_SIZE
);
467 /* Set the context and continue */
468 SetContext(State
, MessageData
, MessageLength
, KdContext
, SendContinue
);
469 return KdPacketReceived
;
475 _Out_ DBGKD_MANIPULATE_STATE64
* State
,
476 _Out_ PSTRING MessageData
,
477 _Out_ PULONG MessageLength
,
478 _Inout_ PKD_CONTEXT KdContext
)
480 if (strncmp(gdb_input
, "vCont", 5) == 0)
482 if (gdb_input
[5] == '?')
485 /* Report what we support */
486 send_gdb_packet("vCont;c;C;s;S");
487 Status
= gdb_receive_packet(KdContext
);
488 if (Status
!= KdPacketReceived
)
490 return gdb_interpret_input(State
, MessageData
, MessageLength
, KdContext
);
493 if (strcmp(gdb_input
, "vCont;c") == 0)
495 DBGKM_EXCEPTION64
* Exception
= NULL
;
497 if (CurrentStateChange
.NewState
== DbgKdExceptionStateChange
)
498 Exception
= &CurrentStateChange
.u
.Exception
;
500 /* See if we should update the program counter (unlike windbg, gdb doesn't do it for us) */
501 if (Exception
&& (Exception
->ExceptionRecord
.ExceptionCode
== STATUS_BREAKPOINT
)
502 && (Exception
->ExceptionRecord
.ExceptionInformation
[0] == 0))
504 /* So we get the context, update it and send it back */
505 GetCurrentContext(State
, MessageData
, MessageLength
, KdContext
, UpdateProgramCounterSendContinue
);
506 return KdPacketReceived
;
509 return SendContinue(State
, MessageData
, MessageLength
, KdContext
);
513 return KdPacketReceived
;
516 /* GLOBAL FUNCTIONS ***********************************************************/
519 _Out_ DBGKD_MANIPULATE_STATE64
* State
,
520 _Out_ PSTRING MessageData
,
521 _Out_ PULONG MessageLength
,
522 _Inout_ PKD_CONTEXT KdContext
)
525 switch (gdb_input
[0])
528 /* Send the Status */
529 gdb_send_exception();
532 gdb_send_registers();
535 handle_gdb_set_thread();
538 return handle_gdb_read_mem(State
, MessageData
, MessageLength
);
540 handle_gdb_query(KdContext
);
543 handle_gdb_thread_alive();
546 return handle_gdb_v(State
, MessageData
, MessageLength
, KdContext
);
548 /* We don't know how to handle this request. Maybe this is something for KD */
549 State
->ReturnStatus
= STATUS_NOT_SUPPORTED
;
550 return KdPacketReceived
;
552 /* Get the answer from GDB */
553 Status
= gdb_receive_packet(KdContext
);
554 if (Status
!= KdPacketReceived
)
556 /* Try interpreting this new packet */
557 return gdb_interpret_input(State
, MessageData
, MessageLength
, KdContext
);