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.
10 /* LOCALS *********************************************************************/
11 static ULONG_PTR gdb_run_tid
;
12 /* Keep track of where we are for qfThreadInfo/qsThreadInfo */
13 static LIST_ENTRY
* CurrentProcessEntry
;
14 static LIST_ENTRY
* CurrentThreadEntry
;
16 /* GLOBALS ********************************************************************/
20 /* PRIVATE FUNCTIONS **********************************************************/
23 hex_to_tid(char* buffer
)
29 hex
= hex_value(*buffer
++);
37 #define hex_to_pid hex_to_tid
41 hex_to_address(char* buffer
)
47 hex
= hex_value(*buffer
++);
59 handle_gdb_set_thread(void)
64 if (strcmp(&gdb_input
[2], "-1") == 0)
65 gdb_run_tid
= (ULONG_PTR
)-1;
67 gdb_run_tid
= hex_to_tid(&gdb_input
[2]);
68 send_gdb_packet("OK");
71 KDDBGPRINT("Setting debug thread: %s.\n", gdb_input
);
72 if (strncmp(&gdb_input
[2], "p-1", 3) == 0)
74 gdb_dbg_pid
= (UINT_PTR
)-1;
75 gdb_dbg_tid
= (UINT_PTR
)-1;
79 char* ptr
= strstr(gdb_input
, ".") + 1;
80 gdb_dbg_pid
= hex_to_pid(&gdb_input
[3]);
81 if (strncmp(ptr
, "-1", 2) == 0)
82 gdb_dbg_tid
= (UINT_PTR
)-1;
84 gdb_dbg_tid
= hex_to_tid(ptr
);
86 send_gdb_packet("OK");
89 KDDBGPRINT("KDGBD: Unknown 'H' command: %s\n", gdb_input
);
95 gdb_receive_and_interpret_packet(
96 _Out_ DBGKD_MANIPULATE_STATE64
* State
,
97 _Out_ PSTRING MessageData
,
98 _Out_ PULONG MessageLength
,
99 _Inout_ PKD_CONTEXT KdContext
)
101 KDSTATUS Status
= gdb_receive_packet(KdContext
);
103 if (Status
!= KdPacketReceived
)
105 return gdb_interpret_input(State
, MessageData
, MessageLength
, KdContext
);
110 handle_gdb_thread_alive(void)
115 Pid
= hex_to_pid(&gdb_input
[2]);
116 Tid
= hex_to_tid(strstr(gdb_input
, ".") + 1);
118 /* We cannot use PsLookupProcessThreadByCid as we could be running at any IRQL.
120 KDDBGPRINT("Checking if p%p.%p is alive.\n", Pid
, Tid
);
122 Thread
= find_thread(Pid
, Tid
);
125 send_gdb_packet("OK");
127 send_gdb_packet("E03");
134 _Out_ DBGKD_MANIPULATE_STATE64
* State
,
135 _Out_ PSTRING MessageData
,
136 _Out_ PULONG MessageLength
,
137 _Inout_ PKD_CONTEXT KdContext
)
139 if (strncmp(gdb_input
, "qSupported:", 11) == 0)
141 send_gdb_packet("PacketSize=4096;multiprocess+;");
142 return gdb_receive_and_interpret_packet(State
, MessageData
, MessageLength
, KdContext
);
145 if (strncmp(gdb_input
, "qAttached", 9) == 0)
147 /* Say no: We didn't attach, we create the process! */
148 send_gdb_packet("0");
149 return gdb_receive_and_interpret_packet(State
, MessageData
, MessageLength
, KdContext
);
152 if (strncmp(gdb_input
, "qRcmd,", 6) == 0)
154 send_gdb_packet("OK");
155 return gdb_receive_and_interpret_packet(State
, MessageData
, MessageLength
, KdContext
);
158 if (strcmp(gdb_input
, "qC") == 0)
161 sprintf(gdb_out
, "QC:p%"PRIxPTR
".%"PRIxPTR
";",
162 handle_to_gdb_pid(PsGetThreadProcessId((PETHREAD
)(ULONG_PTR
)CurrentStateChange
.Thread
)),
163 handle_to_gdb_tid(PsGetThreadId((PETHREAD
)(ULONG_PTR
)CurrentStateChange
.Thread
)));
164 send_gdb_packet(gdb_out
);
165 return gdb_receive_and_interpret_packet(State
, MessageData
, MessageLength
, KdContext
);
168 if ((strncmp(gdb_input
, "qfThreadInfo", 12) == 0)
169 || (strncmp(gdb_input
, "qsThreadInfo", 12) == 0))
171 BOOLEAN FirstThread
= TRUE
;
176 BOOLEAN Resuming
= strncmp(gdb_input
, "qsThreadInfo", 12) == 0;
180 if (CurrentProcessEntry
== (LIST_ENTRY
*)1)
183 send_gdb_packet("l");
184 CurrentProcessEntry
= NULL
;
185 return gdb_receive_and_interpret_packet(State
, MessageData
, MessageLength
, KdContext
);
188 if (CurrentThreadEntry
== NULL
)
189 CurrentProcessEntry
= CurrentProcessEntry
->Flink
;
192 CurrentProcessEntry
= ProcessListHead
->Flink
;
194 if ((CurrentProcessEntry
== ProcessListHead
) ||
195 (CurrentProcessEntry
== NULL
)) /* Ps is not initialized */
197 /* We're almost done. Tell GDB about the idle thread */
198 send_gdb_packet("mp1.1");
199 CurrentProcessEntry
= (LIST_ENTRY
*)1;
200 return gdb_receive_and_interpret_packet(State
, MessageData
, MessageLength
, KdContext
);
203 Process
= CONTAINING_RECORD(CurrentProcessEntry
, EPROCESS
, ActiveProcessLinks
);
205 if (Resuming
&& CurrentThreadEntry
!= NULL
)
206 CurrentThreadEntry
= CurrentThreadEntry
->Flink
;
208 CurrentThreadEntry
= Process
->ThreadListHead
.Flink
;
213 /* List threads from this process */
215 CurrentThreadEntry
!= &Process
->ThreadListHead
;
216 CurrentThreadEntry
= CurrentThreadEntry
->Flink
)
218 Thread
= CONTAINING_RECORD(CurrentThreadEntry
, ETHREAD
, ThreadListEntry
);
220 /* See if we should add a comma */
230 ptr
+= _snprintf(ptr
, 1024 - (ptr
- gdb_out
),
232 handle_to_gdb_pid(Process
->UniqueProcessId
),
233 handle_to_gdb_tid(Thread
->Cid
.UniqueThread
));
234 if (ptr
> (gdb_out
+ 1024))
236 /* send what we got */
237 send_gdb_packet(gdb_out
);
238 /* GDB can ask anything at this point, it isn't necessarily a qsThreadInfo packet */
239 return gdb_receive_and_interpret_packet(State
, MessageData
, MessageLength
, KdContext
);
243 /* send the list for this process */
244 send_gdb_packet(gdb_out
);
245 CurrentThreadEntry
= NULL
;
246 /* GDB can ask anything at this point, it isn't necessarily a qsThreadInfo packet */
247 return gdb_receive_and_interpret_packet(State
, MessageData
, MessageLength
, KdContext
);
250 KDDBGPRINT("KDGDB: Unknown query: %s\n", gdb_input
);
252 return gdb_receive_and_interpret_packet(State
, MessageData
, MessageLength
, KdContext
);
258 handle_gdb_registers(
259 _Out_ DBGKD_MANIPULATE_STATE64
* State
,
260 _Out_ PSTRING MessageData
,
261 _Out_ PULONG MessageLength
)
265 KDDBGPRINT("Should get registers from other thread!\n");
268 State
->ApiNumber
= DbgKdGetContextApi
;
269 State
->ReturnStatus
= STATUS_SUCCESS
; /* ? */
270 State
->Processor
= CurrentStateChange
.Processor
;
271 State
->ProcessorLevel
= CurrentStateChange
.ProcessorLevel
;
273 MessageData
->Length
= 0;
275 return KdPacketReceived
;
281 ReadMemorySendHandler(
282 _In_ ULONG PacketType
,
283 _In_ PSTRING MessageHeader
,
284 _In_ PSTRING MessageData
)
286 DBGKD_MANIPULATE_STATE64
* State
= (DBGKD_MANIPULATE_STATE64
*)MessageHeader
->Buffer
;
288 if (PacketType
!= PACKET_TYPE_KD_STATE_MANIPULATE
)
291 KDDBGPRINT("Wrong packet type (%lu) received after DbgKdReadVirtualMemoryApi request.\n", PacketType
);
295 if (State
->ApiNumber
!= DbgKdReadVirtualMemoryApi
)
297 KDDBGPRINT("Wrong API number (%lu) after DbgKdReadVirtualMemoryApi request.\n", State
->ApiNumber
);
301 if (!NT_SUCCESS(State
->ReturnStatus
))
302 send_gdb_ntstatus(State
->ReturnStatus
);
304 send_gdb_memory(MessageData
->Buffer
, MessageData
->Length
);
305 KdpSendPacketHandler
= NULL
;
306 KdpManipulateStateHandler
= NULL
;
309 if ((gdb_dbg_pid
!= 0) && gdb_pid_to_handle(gdb_dbg_pid
) != PsGetCurrentProcessId())
311 __writecr3(PsGetCurrentProcess()->Pcb
.DirectoryTableBase
[0]);
318 _Out_ DBGKD_MANIPULATE_STATE64
* State
,
319 _Out_ PSTRING MessageData
,
320 _Out_ PULONG MessageLength
,
321 _Inout_ PKD_CONTEXT KdContext
)
323 State
->ApiNumber
= DbgKdReadVirtualMemoryApi
;
324 State
->ReturnStatus
= STATUS_SUCCESS
; /* ? */
325 State
->Processor
= CurrentStateChange
.Processor
;
326 State
->ProcessorLevel
= CurrentStateChange
.ProcessorLevel
;
328 MessageData
->Length
= 0;
331 /* Set the TLB according to the process being read. Pid 0 means any process. */
332 if ((gdb_dbg_pid
!= 0) && gdb_pid_to_handle(gdb_dbg_pid
) != PsGetCurrentProcessId())
334 PEPROCESS AttachedProcess
= find_process(gdb_dbg_pid
);
335 if (AttachedProcess
== NULL
)
337 KDDBGPRINT("The current GDB debug thread is invalid!");
338 send_gdb_packet("E03");
339 return gdb_receive_and_interpret_packet(State
, MessageData
, MessageLength
, KdContext
);
341 __writecr3(AttachedProcess
->Pcb
.DirectoryTableBase
[0]);
344 State
->u
.ReadMemory
.TargetBaseAddress
= hex_to_address(&gdb_input
[1]);
345 State
->u
.ReadMemory
.TransferCount
= hex_to_address(strstr(&gdb_input
[1], ",") + 1);
347 /* KD will reply with KdSendPacket. Catch it */
348 KdpSendPacketHandler
= ReadMemorySendHandler
;
350 return KdPacketReceived
;
356 _Out_ DBGKD_MANIPULATE_STATE64
* State
,
357 _Out_ PSTRING MessageData
,
358 _Out_ PULONG MessageLength
,
359 _Inout_ PKD_CONTEXT KdContext
)
361 if (strncmp(gdb_input
, "vCont", 5) == 0)
363 if (gdb_input
[5] == '?')
366 /* Report what we support */
367 send_gdb_packet("vCont;c;C;s;S");
368 Status
= gdb_receive_packet(KdContext
);
369 if (Status
!= KdPacketReceived
)
371 return gdb_interpret_input(State
, MessageData
, MessageLength
, KdContext
);
374 if (strcmp(gdb_input
, "vCont;c") == 0)
376 DBGKM_EXCEPTION64
* Exception
= NULL
;
378 /* Tell GDB everything is fine, we will handle it */
379 send_gdb_packet("OK");
381 if (CurrentStateChange
.NewState
== DbgKdExceptionStateChange
)
382 Exception
= &CurrentStateChange
.u
.Exception
;
384 /* See if we should update the program counter (unlike windbg, gdb doesn't do it for us) */
385 if (Exception
&& (Exception
->ExceptionRecord
.ExceptionCode
== STATUS_BREAKPOINT
)
386 && (Exception
->ExceptionRecord
.ExceptionInformation
[0] == 0))
388 ULONG_PTR ProgramCounter
;
390 /* So we must get past the breakpoint instruction */
391 ProgramCounter
= KdpGetContextPc(&CurrentContext
);
392 KdpSetContextPc(&CurrentContext
, ProgramCounter
+ KD_BREAKPOINT_SIZE
);
394 SetContextManipulateHandler(State
, MessageData
, MessageLength
, KdContext
);
395 KdpManipulateStateHandler
= ContinueManipulateStateHandler
;
396 return KdPacketReceived
;
399 return ContinueManipulateStateHandler(State
, MessageData
, MessageLength
, KdContext
);
403 KDDBGPRINT("Unhandled 'v' packet: %s\n", gdb_input
);
404 return KdPacketReceived
;
407 /* GLOBAL FUNCTIONS ***********************************************************/
410 _Out_ DBGKD_MANIPULATE_STATE64
* State
,
411 _Out_ PSTRING MessageData
,
412 _Out_ PULONG MessageLength
,
413 _Inout_ PKD_CONTEXT KdContext
)
415 switch (gdb_input
[0])
418 /* Send the Status */
419 gdb_send_exception();
422 return gdb_send_registers(State
, MessageData
, MessageLength
, KdContext
);
424 handle_gdb_set_thread();
427 return handle_gdb_read_mem(State
, MessageData
, MessageLength
, KdContext
);
429 return gdb_send_register(State
, MessageData
, MessageLength
, KdContext
);
431 return handle_gdb_query(State
, MessageData
, MessageLength
, KdContext
);
433 handle_gdb_thread_alive();
436 return handle_gdb_v(State
, MessageData
, MessageLength
, KdContext
);
438 /* We don't know how to handle this request. Maybe this is something for KD */
439 State
->ReturnStatus
= STATUS_NOT_SUPPORTED
;
440 KDDBGPRINT("Unsupported GDB command: %s.\n", gdb_input
);
441 return KdPacketReceived
;
443 return gdb_receive_and_interpret_packet(State
, MessageData
, MessageLength
, KdContext
);