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 /* Keep track of where we are for qfThreadInfo/qsThreadInfo */
15 static LIST_ENTRY
* CurrentProcessEntry
;
16 static LIST_ENTRY
* CurrentThreadEntry
;
18 /* GLOBALS ********************************************************************/
19 HANDLE gdb_dbg_process
;
20 HANDLE gdb_dbg_thread
;
22 /* PRIVATE FUNCTIONS **********************************************************/
25 hex_to_thread(char* buffer
)
31 hex
= hex_value(*buffer
++);
42 hex_to_address(char* buffer
)
48 hex
= hex_value(*buffer
++);
60 handle_gdb_set_thread(void)
65 if (strcmp(&gdb_input
[2], "-1") == 0)
66 gdb_run_thread
= (HANDLE
)-1;
68 gdb_run_thread
= hex_to_thread(&gdb_input
[2]);
69 send_gdb_packet("OK");
72 KDDBGPRINT("Setting debug thread: %s.\n", gdb_input
);
73 if (strncmp(&gdb_input
[2], "p-1", 3) == 0)
75 gdb_dbg_process
= (HANDLE
)-1;
76 gdb_dbg_thread
= (HANDLE
)-1;
80 char* ptr
= strstr(gdb_input
, ".") + 1;
81 gdb_dbg_process
= hex_to_thread(&gdb_input
[3]);
82 if (strncmp(ptr
, "-1", 2) == 0)
83 gdb_dbg_thread
= (HANDLE
)-1;
85 gdb_dbg_thread
= hex_to_thread(ptr
);
87 send_gdb_packet("OK");
90 KDDBGPRINT("KDGBD: Unknown 'H' command: %s\n", gdb_input
);
96 gdb_receive_and_interpret_packet(
97 _Out_ DBGKD_MANIPULATE_STATE64
* State
,
98 _Out_ PSTRING MessageData
,
99 _Out_ PULONG MessageLength
,
100 _Inout_ PKD_CONTEXT KdContext
)
102 KDSTATUS Status
= gdb_receive_packet(KdContext
);
104 if (Status
!= KdPacketReceived
)
106 return gdb_interpret_input(State
, MessageData
, MessageLength
, KdContext
);
111 handle_gdb_thread_alive(void)
113 char* ptr
= strstr(gdb_input
, ".") + 1;
118 ClientId
.UniqueProcess
= hex_to_thread(&gdb_input
[2]);
119 ClientId
.UniqueThread
= hex_to_thread(ptr
);
121 Status
= PsLookupProcessThreadByCid(&ClientId
, NULL
, &Thread
);
123 if (!NT_SUCCESS(Status
))
125 /* Thread doesn't exist */
126 send_gdb_packet("E03");
131 ObDereferenceObject(Thread
);
132 send_gdb_packet("OK");
139 _Out_ DBGKD_MANIPULATE_STATE64
* State
,
140 _Out_ PSTRING MessageData
,
141 _Out_ PULONG MessageLength
,
142 _Inout_ PKD_CONTEXT KdContext
)
144 if (strncmp(gdb_input
, "qSupported:", 11) == 0)
146 send_gdb_packet("PacketSize=4096;multiprocess+;");
147 return gdb_receive_and_interpret_packet(State
, MessageData
, MessageLength
, KdContext
);
150 if (strncmp(gdb_input
, "qAttached", 9) == 0)
152 /* Say no: We didn't attach, we create the process! */
153 send_gdb_packet("0");
154 return gdb_receive_and_interpret_packet(State
, MessageData
, MessageLength
, KdContext
);
157 if (strncmp(gdb_input
, "qRcmd,", 6) == 0)
159 send_gdb_packet("OK");
160 return gdb_receive_and_interpret_packet(State
, MessageData
, MessageLength
, KdContext
);
163 if (strcmp(gdb_input
, "qC") == 0)
166 sprintf(gdb_out
, "QC:p%p.%p;",
167 PsGetThreadProcessId((PETHREAD
)(ULONG_PTR
)CurrentStateChange
.Thread
),
168 PsGetThreadId((PETHREAD
)(ULONG_PTR
)CurrentStateChange
.Thread
));
169 send_gdb_packet(gdb_out
);
170 return gdb_receive_and_interpret_packet(State
, MessageData
, MessageLength
, KdContext
);
173 if ((strncmp(gdb_input
, "qfThreadInfo", 12) == 0)
174 || (strncmp(gdb_input
, "qsThreadInfo", 12) == 0))
176 LIST_ENTRY
* ProcessListHead
= (LIST_ENTRY
*)KdDebuggerDataBlock
->PsActiveProcessHead
.Pointer
;
177 BOOLEAN FirstThread
= TRUE
;
182 BOOLEAN Resuming
= strncmp(gdb_input
, "qsThreadInfo", 12) == 0;
184 /* Maybe this was not initialized yet */
185 if (!ProcessListHead
->Flink
)
191 /* there is only one thread to tell about */
192 send_gdb_packet("l");
193 return gdb_receive_and_interpret_packet(State
, MessageData
, MessageLength
, KdContext
);
195 /* Just tell GDB about the current thread */
196 sprintf(gdb_out
, "mp%p.%p", PsGetCurrentProcessId(), PsGetCurrentThreadId());
197 send_gdb_packet(gdb_out
);
198 /* GDB can ask anything at this point, it isn't necessarily a qsThreadInfo packet */
199 return gdb_receive_and_interpret_packet(State
, MessageData
, MessageLength
, KdContext
);
204 if (CurrentThreadEntry
== NULL
)
205 CurrentProcessEntry
= CurrentProcessEntry
->Flink
;
208 CurrentProcessEntry
= ProcessListHead
->Flink
;
210 if (CurrentProcessEntry
== ProcessListHead
)
213 send_gdb_packet("l");
214 return gdb_receive_and_interpret_packet(State
, MessageData
, MessageLength
, KdContext
);
217 Process
= CONTAINING_RECORD(CurrentProcessEntry
, EPROCESS
, ActiveProcessLinks
);
219 if (Resuming
&& CurrentThreadEntry
!= NULL
)
220 CurrentThreadEntry
= CurrentThreadEntry
->Flink
;
222 CurrentThreadEntry
= Process
->ThreadListHead
.Flink
;
227 /* List threads from this process */
229 CurrentThreadEntry
!= &Process
->ThreadListHead
;
230 CurrentThreadEntry
= CurrentThreadEntry
->Flink
)
232 Thread
= CONTAINING_RECORD(CurrentThreadEntry
, ETHREAD
, ThreadListEntry
);
234 /* See if we should add a comma */
244 ptr
+= _snprintf(ptr
, 1024 - (ptr
- gdb_out
),
245 "p%p.%p", PsGetProcessId(Process
), PsGetThreadId(Thread
));
246 if (ptr
> (gdb_out
+ 1024))
248 /* send what we got */
249 send_gdb_packet(gdb_out
);
250 /* GDB can ask anything at this point, it isn't necessarily a qsThreadInfo packet */
251 return gdb_receive_and_interpret_packet(State
, MessageData
, MessageLength
, KdContext
);
255 /* send the list for this process */
256 send_gdb_packet(gdb_out
);
257 CurrentThreadEntry
= NULL
;
258 /* GDB can ask anything at this point, it isn't necessarily a qsThreadInfo packet */
259 return gdb_receive_and_interpret_packet(State
, MessageData
, MessageLength
, KdContext
);
262 KDDBGPRINT("KDGDB: Unknown query: %s\n", gdb_input
);
264 return gdb_receive_and_interpret_packet(State
, MessageData
, MessageLength
, KdContext
);
270 handle_gdb_registers(
271 _Out_ DBGKD_MANIPULATE_STATE64
* State
,
272 _Out_ PSTRING MessageData
,
273 _Out_ PULONG MessageLength
)
277 KDDBGPRINT("Should get registers from other thread!\n");
280 State
->ApiNumber
= DbgKdGetContextApi
;
281 State
->ReturnStatus
= STATUS_SUCCESS
; /* ? */
282 State
->Processor
= CurrentStateChange
.Processor
;
283 State
->ProcessorLevel
= CurrentStateChange
.ProcessorLevel
;
285 MessageData
->Length
= 0;
287 return KdPacketReceived
;
293 ReadMemorySendHandler(
294 _In_ ULONG PacketType
,
295 _In_ PSTRING MessageHeader
,
296 _In_ PSTRING MessageData
)
298 DBGKD_MANIPULATE_STATE64
* State
= (DBGKD_MANIPULATE_STATE64
*)MessageHeader
->Buffer
;
300 if (PacketType
!= PACKET_TYPE_KD_STATE_MANIPULATE
)
303 KDDBGPRINT("Wrong packet type (%lu) received after DbgKdReadVirtualMemoryApi request.\n", PacketType
);
307 if (State
->ApiNumber
!= DbgKdReadVirtualMemoryApi
)
309 KDDBGPRINT("Wrong API number (%lu) after DbgKdReadVirtualMemoryApi request.\n", State
->ApiNumber
);
313 if (!NT_SUCCESS(State
->ReturnStatus
))
314 send_gdb_ntstatus(State
->ReturnStatus
);
316 send_gdb_memory(MessageData
->Buffer
, MessageData
->Length
);
317 KdpSendPacketHandler
= NULL
;
318 KdpManipulateStateHandler
= NULL
;
324 _Out_ DBGKD_MANIPULATE_STATE64
* State
,
325 _Out_ PSTRING MessageData
,
326 _Out_ PULONG MessageLength
)
328 State
->ApiNumber
= DbgKdReadVirtualMemoryApi
;
329 State
->ReturnStatus
= STATUS_SUCCESS
; /* ? */
330 State
->Processor
= CurrentStateChange
.Processor
;
331 State
->ProcessorLevel
= CurrentStateChange
.ProcessorLevel
;
333 MessageData
->Length
= 0;
336 State
->u
.ReadMemory
.TargetBaseAddress
= hex_to_address(&gdb_input
[1]);
337 State
->u
.ReadMemory
.TransferCount
= hex_to_address(strstr(&gdb_input
[1], ",") + 1);
339 /* KD will reply with KdSendPacket. Catch it */
340 KdpSendPacketHandler
= ReadMemorySendHandler
;
342 return KdPacketReceived
;
348 _Out_ DBGKD_MANIPULATE_STATE64
* State
,
349 _Out_ PSTRING MessageData
,
350 _Out_ PULONG MessageLength
,
351 _Inout_ PKD_CONTEXT KdContext
)
353 if (strncmp(gdb_input
, "vCont", 5) == 0)
355 if (gdb_input
[5] == '?')
358 /* Report what we support */
359 send_gdb_packet("vCont;c;C;s;S");
360 Status
= gdb_receive_packet(KdContext
);
361 if (Status
!= KdPacketReceived
)
363 return gdb_interpret_input(State
, MessageData
, MessageLength
, KdContext
);
366 if (strcmp(gdb_input
, "vCont;c") == 0)
368 DBGKM_EXCEPTION64
* Exception
= NULL
;
370 /* Tell GDB everything is fine, we will handle it */
371 send_gdb_packet("OK");
373 if (CurrentStateChange
.NewState
== DbgKdExceptionStateChange
)
374 Exception
= &CurrentStateChange
.u
.Exception
;
376 /* See if we should update the program counter (unlike windbg, gdb doesn't do it for us) */
377 if (Exception
&& (Exception
->ExceptionRecord
.ExceptionCode
== STATUS_BREAKPOINT
)
378 && (Exception
->ExceptionRecord
.ExceptionInformation
[0] == 0))
380 ULONG_PTR ProgramCounter
;
382 /* So we must get past the breakpoint instruction */
383 ProgramCounter
= KdpGetContextPc(&CurrentContext
);
384 KdpSetContextPc(&CurrentContext
, ProgramCounter
+ KD_BREAKPOINT_SIZE
);
386 SetContextManipulateHandler(State
, MessageData
, MessageLength
, KdContext
);
387 KdpManipulateStateHandler
= ContinueManipulateStateHandler
;
388 return KdPacketReceived
;
391 return ContinueManipulateStateHandler(State
, MessageData
, MessageLength
, KdContext
);
395 KDDBGPRINT("Unhandled 'v' packet: %s\n", gdb_input
);
396 return KdPacketReceived
;
399 /* GLOBAL FUNCTIONS ***********************************************************/
402 _Out_ DBGKD_MANIPULATE_STATE64
* State
,
403 _Out_ PSTRING MessageData
,
404 _Out_ PULONG MessageLength
,
405 _Inout_ PKD_CONTEXT KdContext
)
407 switch (gdb_input
[0])
410 /* Send the Status */
411 gdb_send_exception();
414 return gdb_send_registers(State
, MessageData
, MessageLength
, KdContext
);
416 handle_gdb_set_thread();
419 return handle_gdb_read_mem(State
, MessageData
, MessageLength
);
421 return gdb_send_register(State
, MessageData
, MessageLength
, KdContext
);
423 return handle_gdb_query(State
, MessageData
, MessageLength
, KdContext
);
425 handle_gdb_thread_alive();
428 return handle_gdb_v(State
, MessageData
, MessageLength
, KdContext
);
430 /* We don't know how to handle this request. Maybe this is something for KD */
431 State
->ReturnStatus
= STATUS_NOT_SUPPORTED
;
432 KDDBGPRINT("Unsupported GDB command: %s.\n", gdb_input
);
433 return KdPacketReceived
;
435 return gdb_receive_and_interpret_packet(State
, MessageData
, MessageLength
, KdContext
);