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
;
281 _Out_ DBGKD_MANIPULATE_STATE64
* State
,
282 _Out_ PSTRING MessageData
,
283 _Out_ PULONG MessageLength
)
285 State
->ApiNumber
= DbgKdReadVirtualMemoryApi
;
286 State
->ReturnStatus
= STATUS_SUCCESS
; /* ? */
287 State
->Processor
= CurrentStateChange
.Processor
;
288 State
->ProcessorLevel
= CurrentStateChange
.ProcessorLevel
;
290 MessageData
->Length
= 0;
293 State
->u
.ReadMemory
.TargetBaseAddress
= hex_to_address(&gdb_input
[1]);
294 State
->u
.ReadMemory
.TransferCount
= hex_to_address(strstr(&gdb_input
[1], ",") + 1);
295 return KdPacketReceived
;
300 GetCurrentContextSendHandler(
301 _In_ ULONG PacketType
,
302 _In_ PSTRING MessageHeader
,
303 _In_ PSTRING MessageData
306 DBGKD_MANIPULATE_STATE64
* State
= (DBGKD_MANIPULATE_STATE64
*)MessageHeader
->Buffer
;
307 const CONTEXT
* Context
= (const CONTEXT
*)MessageData
->Buffer
;
309 if ((PacketType
!= PACKET_TYPE_KD_STATE_MANIPULATE
)
310 || (State
->ApiNumber
!= DbgKdGetContextApi
)
311 || (MessageData
->Length
< sizeof(*Context
)))
313 /* Should we bugcheck ? */
318 RtlCopyMemory(&CurrentContext
, Context
, sizeof(*Context
));
324 _Out_ DBGKD_MANIPULATE_STATE64
* State
,
325 _Out_ PSTRING MessageData
,
326 _Out_ PULONG MessageLength
,
327 _Inout_ PKD_CONTEXT KdContext
,
328 _In_opt_ KDP_MANIPULATESTATE_HANDLER ManipulateStateHandler
331 State
->ApiNumber
= DbgKdGetContextApi
;
332 State
->Processor
= CurrentStateChange
.Processor
;
333 State
->ReturnStatus
= STATUS_SUCCESS
;
334 State
->ProcessorLevel
= CurrentStateChange
.ProcessorLevel
;
335 MessageData
->Length
= 0;
337 /* Update the send <-> receive loop handler */
338 KdpSendPacketHandler
= GetCurrentContextSendHandler
;
339 KdpManipulateStateHandler
= ManipulateStateHandler
;
344 SetContextSendHandler(
345 _In_ ULONG PacketType
,
346 _In_ PSTRING MessageHeader
,
347 _In_ PSTRING MessageData
350 DBGKD_MANIPULATE_STATE64
* State
= (DBGKD_MANIPULATE_STATE64
*)MessageHeader
->Buffer
;
352 /* We just confirm that all went well */
353 if ((PacketType
!= PACKET_TYPE_KD_STATE_MANIPULATE
)
354 || (State
->ApiNumber
!= DbgKdSetContextApi
)
355 || (State
->ReturnStatus
!= STATUS_SUCCESS
))
357 /* Should we bugcheck ? */
365 _Out_ DBGKD_MANIPULATE_STATE64
* State
,
366 _Out_ PSTRING MessageData
,
367 _Out_ PULONG MessageLength
,
368 _Inout_ PKD_CONTEXT KdContext
,
369 _In_opt_ KDP_MANIPULATESTATE_HANDLER ManipulateStateHandler
372 State
->ApiNumber
= DbgKdSetContextApi
;
373 State
->Processor
= CurrentStateChange
.Processor
;
374 State
->ReturnStatus
= STATUS_SUCCESS
;
375 State
->ProcessorLevel
= CurrentStateChange
.ProcessorLevel
;
376 MessageData
->Length
= sizeof(CurrentContext
);
378 if (MessageData
->MaximumLength
< sizeof(CurrentContext
))
383 RtlCopyMemory(MessageData
->Buffer
, &CurrentContext
, sizeof(CurrentContext
));
385 /* Update the send <-> receive loop handlers */
386 KdpSendPacketHandler
= SetContextSendHandler
;
387 KdpManipulateStateHandler
= ManipulateStateHandler
;
389 return KdPacketReceived
;
395 _Out_ DBGKD_MANIPULATE_STATE64
* State
,
396 _Out_ PSTRING MessageData
,
397 _Out_ PULONG MessageLength
,
398 _Inout_ PKD_CONTEXT KdContext
402 State
->ApiNumber
= DbgKdContinueApi
;
403 State
->ReturnStatus
= STATUS_SUCCESS
; /* ? */
404 State
->Processor
= CurrentStateChange
.Processor
;
405 State
->ProcessorLevel
= CurrentStateChange
.ProcessorLevel
;
407 MessageData
->Length
= 0;
409 State
->u
.Continue
.ContinueStatus
= STATUS_SUCCESS
;
411 /* We definitely are at the end of the send <-> receive loop, if any */
412 KdpSendPacketHandler
= NULL
;
413 KdpManipulateStateHandler
= NULL
;
415 /* Tell GDB we are fine */
416 send_gdb_packet("OK");
417 return KdPacketReceived
;
422 UpdateProgramCounterSendContinue(
423 _Out_ DBGKD_MANIPULATE_STATE64
* State
,
424 _Out_ PSTRING MessageData
,
425 _Out_ PULONG MessageLength
,
426 _Inout_ PKD_CONTEXT KdContext
)
428 ULONG_PTR ProgramCounter
;
430 /* So we must get past the breakpoint instruction */
431 ProgramCounter
= KdpGetContextPc(&CurrentContext
);
432 KdpSetContextPc(&CurrentContext
, ProgramCounter
+ KD_BREAKPOINT_SIZE
);
434 /* Set the context and continue */
435 SetContext(State
, MessageData
, MessageLength
, KdContext
, SendContinue
);
436 return KdPacketReceived
;
442 _Out_ DBGKD_MANIPULATE_STATE64
* State
,
443 _Out_ PSTRING MessageData
,
444 _Out_ PULONG MessageLength
,
445 _Inout_ PKD_CONTEXT KdContext
)
447 if (strncmp(gdb_input
, "vCont", 5) == 0)
449 if (gdb_input
[5] == '?')
452 /* Report what we support */
453 send_gdb_packet("vCont;c;C;s;S");
454 Status
= gdb_receive_packet(KdContext
);
455 if (Status
!= KdPacketReceived
)
457 return gdb_interpret_input(State
, MessageData
, MessageLength
, KdContext
);
460 if (strcmp(gdb_input
, "vCont;c") == 0)
462 DBGKM_EXCEPTION64
* Exception
= NULL
;
464 if (CurrentStateChange
.NewState
== DbgKdExceptionStateChange
)
465 Exception
= &CurrentStateChange
.u
.Exception
;
467 /* See if we should update the program counter (unlike windbg, gdb doesn't do it for us) */
468 if (Exception
&& (Exception
->ExceptionRecord
.ExceptionCode
== STATUS_BREAKPOINT
)
469 && (Exception
->ExceptionRecord
.ExceptionInformation
[0] == 0))
471 /* So we get the context, update it and send it back */
472 GetCurrentContext(State
, MessageData
, MessageLength
, KdContext
, UpdateProgramCounterSendContinue
);
473 return KdPacketReceived
;
476 return SendContinue(State
, MessageData
, MessageLength
, KdContext
);
480 return KdPacketReceived
;
483 /* GLOBAL FUNCTIONS ***********************************************************/
486 _Out_ DBGKD_MANIPULATE_STATE64
* State
,
487 _Out_ PSTRING MessageData
,
488 _Out_ PULONG MessageLength
,
489 _Inout_ PKD_CONTEXT KdContext
)
492 switch (gdb_input
[0])
495 /* Send the Status */
496 gdb_send_exception();
499 gdb_send_registers();
502 handle_gdb_set_thread();
505 return handle_gdb_read_mem(State
, MessageData
, MessageLength
);
507 handle_gdb_query(KdContext
);
510 handle_gdb_thread_alive();
513 return handle_gdb_v(State
, MessageData
, MessageLength
, KdContext
);
515 /* We don't know how to handle this request. Maybe this is something for KD */
516 State
->ReturnStatus
= STATUS_NOT_SUPPORTED
;
517 return KdPacketReceived
;
519 /* Get the answer from GDB */
520 Status
= gdb_receive_packet(KdContext
);
521 if (Status
!= KdPacketReceived
)
523 /* Try interpreting this new packet */
524 return gdb_interpret_input(State
, MessageData
, MessageLength
, KdContext
);