1 /*
2 * COPYRIGHT: GPL, see COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: drivers/base/kddll/kdpacket.c
5 * PURPOSE: Base functions for the kernel debugger.
6 */
7
8 #include "kdgdb.h"
9
10 /* LOCALS *********************************************************************/
11 static
12 BOOLEAN
13 FirstSendHandler(
14 _In_ ULONG PacketType,
15 _In_ PSTRING MessageHeader,
16 _In_ PSTRING MessageData);
17 static BOOLEAN InException = FALSE;
18
19 /* GLOBALS ********************************************************************/
20 DBGKD_GET_VERSION64 KdVersion;
21 KDDEBUGGER_DATA64* KdDebuggerDataBlock;
22 LIST_ENTRY* ProcessListHead;
23 LIST_ENTRY* ModuleListHead;
24 /* Callbacks used to communicate with KD aside from GDB */
25 KDP_SEND_HANDLER KdpSendPacketHandler = FirstSendHandler;
26 KDP_MANIPULATESTATE_HANDLER KdpManipulateStateHandler = NULL;
27 /* Data describing the current exception */
28 DBGKD_ANY_WAIT_STATE_CHANGE CurrentStateChange;
29 CONTEXT CurrentContext;
30 PEPROCESS TheIdleProcess;
31 PETHREAD TheIdleThread;
32
33 /* PRIVATE FUNCTIONS **********************************************************/
34
35 static
36 BOOLEAN
GetContextSendHandler(_In_ ULONG PacketType,_In_ PSTRING MessageHeader,_In_ PSTRING MessageData)37 GetContextSendHandler(
38 _In_ ULONG PacketType,
39 _In_ PSTRING MessageHeader,
40 _In_ PSTRING MessageData
41 )
42 {
43 DBGKD_MANIPULATE_STATE64* State = (DBGKD_MANIPULATE_STATE64*)MessageHeader->Buffer;
44 const CONTEXT* Context = (const CONTEXT*)MessageData->Buffer;
45
46 if ((PacketType != PACKET_TYPE_KD_STATE_MANIPULATE)
47 || (State->ApiNumber != DbgKdGetContextApi)
48 || (MessageData->Length < sizeof(*Context)))
49 {
50 KDDBGPRINT("ERROR: Received wrong packet from KD.\n");
51 return FALSE;
52 }
53
54 /* Just copy it */
55 RtlCopyMemory(&CurrentContext, Context, sizeof(*Context));
56 KdpSendPacketHandler = NULL;
57 return TRUE;
58 }
59
60 static
61 KDSTATUS
GetContextManipulateHandler(_Out_ DBGKD_MANIPULATE_STATE64 * State,_Out_ PSTRING MessageData,_Out_ PULONG MessageLength,_Inout_ PKD_CONTEXT KdContext)62 GetContextManipulateHandler(
63 _Out_ DBGKD_MANIPULATE_STATE64* State,
64 _Out_ PSTRING MessageData,
65 _Out_ PULONG MessageLength,
66 _Inout_ PKD_CONTEXT KdContext
67 )
68 {
69 State->ApiNumber = DbgKdGetContextApi;
70 State->Processor = CurrentStateChange.Processor;
71 State->ReturnStatus = STATUS_SUCCESS;
72 State->ProcessorLevel = CurrentStateChange.ProcessorLevel;
73 MessageData->Length = 0;
74
75 /* Update the send <-> receive loop handler */
76 KdpSendPacketHandler = GetContextSendHandler;
77 KdpManipulateStateHandler = NULL;
78
79 return KdPacketReceived;
80 }
81
82 static
83 BOOLEAN
SetContextSendHandler(_In_ ULONG PacketType,_In_ PSTRING MessageHeader,_In_ PSTRING MessageData)84 SetContextSendHandler(
85 _In_ ULONG PacketType,
86 _In_ PSTRING MessageHeader,
87 _In_ PSTRING MessageData
88 )
89 {
90 DBGKD_MANIPULATE_STATE64* State = (DBGKD_MANIPULATE_STATE64*)MessageHeader->Buffer;
91
92 /* We just confirm that all went well */
93 if ((PacketType != PACKET_TYPE_KD_STATE_MANIPULATE)
94 || (State->ApiNumber != DbgKdSetContextApi)
95 || (State->ReturnStatus != STATUS_SUCCESS))
96 {
97 /* Should we bugcheck ? */
98 KDDBGPRINT("BAD BAD BAD not manipulating state for sending context.\n");
99 return FALSE;
100 }
101
102 KdpSendPacketHandler = NULL;
103 return TRUE;
104 }
105
106 KDSTATUS
SetContextManipulateHandler(_Out_ DBGKD_MANIPULATE_STATE64 * State,_Out_ PSTRING MessageData,_Out_ PULONG MessageLength,_Inout_ PKD_CONTEXT KdContext)107 SetContextManipulateHandler(
108 _Out_ DBGKD_MANIPULATE_STATE64* State,
109 _Out_ PSTRING MessageData,
110 _Out_ PULONG MessageLength,
111 _Inout_ PKD_CONTEXT KdContext
112 )
113 {
114 State->ApiNumber = DbgKdSetContextApi;
115 State->Processor = CurrentStateChange.Processor;
116 State->ReturnStatus = STATUS_SUCCESS;
117 State->ProcessorLevel = CurrentStateChange.ProcessorLevel;
118 MessageData->Length = sizeof(CurrentContext);
119
120 if (MessageData->MaximumLength < sizeof(CurrentContext))
121 {
122 KDDBGPRINT("Wrong message length %u.\n", MessageData->MaximumLength);
123 while (1);
124 }
125
126 RtlCopyMemory(MessageData->Buffer, &CurrentContext, sizeof(CurrentContext));
127
128 /* Update the send <-> receive loop handlers */
129 KdpSendPacketHandler = SetContextSendHandler;
130 KdpManipulateStateHandler = NULL;
131
132 return KdPacketReceived;
133 }
134
135 static
136 void
send_kd_state_change(DBGKD_ANY_WAIT_STATE_CHANGE * StateChange)137 send_kd_state_change(DBGKD_ANY_WAIT_STATE_CHANGE* StateChange)
138 {
139 InException = TRUE;
140
141 switch (StateChange->NewState)
142 {
143 case DbgKdLoadSymbolsStateChange:
144 case DbgKdExceptionStateChange:
145 {
146 PETHREAD Thread = (PETHREAD)(ULONG_PTR)StateChange->Thread;
147 /* Save current state for later GDB queries */
148 CurrentStateChange = *StateChange;
149 KDDBGPRINT("Exception 0x%08x in thread p%p.%p.\n",
150 StateChange->u.Exception.ExceptionRecord.ExceptionCode,
151 PsGetThreadProcessId(Thread),
152 PsGetThreadId(Thread));
153 /* Set the current debugged process/thread accordingly */
154 gdb_dbg_tid = handle_to_gdb_tid(PsGetThreadId(Thread));
155 #if MONOPROCESS
156 gdb_dbg_pid = 0;
157 #else
158 gdb_dbg_pid = handle_to_gdb_pid(PsGetThreadProcessId(Thread));
159 #endif
160 gdb_send_exception();
161 /* Next receive call will ask for the context */
162 KdpManipulateStateHandler = GetContextManipulateHandler;
163 break;
164 }
165 default:
166 KDDBGPRINT("Unknown StateChange %u.\n", StateChange->NewState);
167 while (1);
168 }
169 }
170
171 static
172 void
send_kd_debug_io(_In_ DBGKD_DEBUG_IO * DebugIO,_In_ PSTRING String)173 send_kd_debug_io(
174 _In_ DBGKD_DEBUG_IO* DebugIO,
175 _In_ PSTRING String)
176 {
177 if (InException)
178 return;
179
180 switch (DebugIO->ApiNumber)
181 {
182 case DbgKdPrintStringApi:
183 case DbgKdGetStringApi:
184 gdb_send_debug_io(String, TRUE);
185 break;
186 default:
187 KDDBGPRINT("Unknown ApiNumber %u.\n", DebugIO->ApiNumber);
188 while (1);
189 }
190 }
191
192 static
193 void
send_kd_state_manipulate(_In_ DBGKD_MANIPULATE_STATE64 * State,_In_ PSTRING MessageData)194 send_kd_state_manipulate(
195 _In_ DBGKD_MANIPULATE_STATE64* State,
196 _In_ PSTRING MessageData)
197 {
198 switch (State->ApiNumber)
199 {
200 #if 0
201 case DbgKdGetContextApi:
202 /* This is an answer to a 'g' GDB request */
203 gdb_send_registers((CONTEXT*)MessageData->Buffer);
204 return;
205 #endif
206 default:
207 KDDBGPRINT("Unknown ApiNumber %u.\n", State->ApiNumber);
208 while (1);
209 }
210 }
211
212 KDSTATUS
ContinueManipulateStateHandler(_Out_ DBGKD_MANIPULATE_STATE64 * State,_Out_ PSTRING MessageData,_Out_ PULONG MessageLength,_Inout_ PKD_CONTEXT KdContext)213 ContinueManipulateStateHandler(
214 _Out_ DBGKD_MANIPULATE_STATE64* State,
215 _Out_ PSTRING MessageData,
216 _Out_ PULONG MessageLength,
217 _Inout_ PKD_CONTEXT KdContext
218 )
219 {
220 /* Let's go on */
221 State->ApiNumber = DbgKdContinueApi;
222 State->ReturnStatus = STATUS_SUCCESS; /* ? */
223 State->Processor = CurrentStateChange.Processor;
224 State->ProcessorLevel = CurrentStateChange.ProcessorLevel;
225 if (MessageData)
226 MessageData->Length = 0;
227 *MessageLength = 0;
228 State->u.Continue.ContinueStatus = STATUS_SUCCESS;
229
230 /* We definitely are at the end of the send <-> receive loop, if any */
231 KdpSendPacketHandler = NULL;
232 KdpManipulateStateHandler = NULL;
233 /* We're not handling an exception anymore */
234 InException = FALSE;
235
236 return KdPacketReceived;
237 }
238
239 static
240 BOOLEAN
GetVersionSendHandler(_In_ ULONG PacketType,_In_ PSTRING MessageHeader,_In_ PSTRING MessageData)241 GetVersionSendHandler(
242 _In_ ULONG PacketType,
243 _In_ PSTRING MessageHeader,
244 _In_ PSTRING MessageData)
245 {
246 DBGKD_MANIPULATE_STATE64* State = (DBGKD_MANIPULATE_STATE64*)MessageHeader->Buffer;
247 PLIST_ENTRY DebuggerDataList;
248
249 /* Confirm that all went well */
250 if ((PacketType != PACKET_TYPE_KD_STATE_MANIPULATE)
251 || (State->ApiNumber != DbgKdGetVersionApi)
252 || !NT_SUCCESS(State->ReturnStatus))
253 {
254 KDDBGPRINT("Wrong packet received after asking for data.\n");
255 return FALSE;
256 }
257
258 /* Copy the relevant data */
259 RtlCopyMemory(&KdVersion, &State->u.GetVersion64, sizeof(KdVersion));
260 DebuggerDataList = *(PLIST_ENTRY*)&KdVersion.DebuggerDataList;
261 KdDebuggerDataBlock = CONTAINING_RECORD(DebuggerDataList->Flink, KDDEBUGGER_DATA64, Header.List);
262 ProcessListHead = *(PLIST_ENTRY*)&KdDebuggerDataBlock->PsActiveProcessHead;
263 ModuleListHead = *(PLIST_ENTRY*)&KdDebuggerDataBlock->PsLoadedModuleList;
264
265 /* Now we can get the context for the current state */
266 KdpSendPacketHandler = NULL;
267 KdpManipulateStateHandler = GetContextManipulateHandler;
268 return TRUE;
269 }
270
271 static
272 KDSTATUS
GetVersionManipulateStateHandler(_Out_ DBGKD_MANIPULATE_STATE64 * State,_Out_ PSTRING MessageData,_Out_ PULONG MessageLength,_Inout_ PKD_CONTEXT KdContext)273 GetVersionManipulateStateHandler(
274 _Out_ DBGKD_MANIPULATE_STATE64* State,
275 _Out_ PSTRING MessageData,
276 _Out_ PULONG MessageLength,
277 _Inout_ PKD_CONTEXT KdContext)
278 {
279 /* Ask for the version data */
280 State->ApiNumber = DbgKdGetVersionApi;
281 State->Processor = CurrentStateChange.Processor;
282 State->ProcessorLevel = CurrentStateChange.ProcessorLevel;
283
284 /* The next send call will serve this query */
285 KdpSendPacketHandler = GetVersionSendHandler;
286 KdpManipulateStateHandler = NULL;
287
288 return KdPacketReceived;
289 }
290
291 static
292 BOOLEAN
FirstSendHandler(_In_ ULONG PacketType,_In_ PSTRING MessageHeader,_In_ PSTRING MessageData)293 FirstSendHandler(
294 _In_ ULONG PacketType,
295 _In_ PSTRING MessageHeader,
296 _In_ PSTRING MessageData)
297 {
298 DBGKD_ANY_WAIT_STATE_CHANGE* StateChange = (DBGKD_ANY_WAIT_STATE_CHANGE*)MessageHeader->Buffer;
299 PETHREAD Thread;
300
301 if (PacketType != PACKET_TYPE_KD_STATE_CHANGE64)
302 {
303 KDDBGPRINT("First KD packet is not a state change!\n");
304 return FALSE;
305 }
306
307 KDDBGPRINT("KDGDB: START!\n");
308
309 Thread = (PETHREAD)(ULONG_PTR)StateChange->Thread;
310
311 /* Set up the current state */
312 CurrentStateChange = *StateChange;
313 gdb_dbg_tid = handle_to_gdb_tid(PsGetThreadId(Thread));
314 #if MONOPROCESS
315 gdb_dbg_pid = 0;
316 #else
317 gdb_dbg_pid = handle_to_gdb_pid(PsGetThreadProcessId(Thread));
318 #endif
319 /* This is the idle process. Save it! */
320 TheIdleThread = Thread;
321 TheIdleProcess = (PEPROCESS)Thread->Tcb.ApcState.Process;
322
323 KDDBGPRINT("Pid Tid of the first message: %" PRIxPTR", %" PRIxPTR ".\n", gdb_dbg_pid, gdb_dbg_tid);
324
325 /* The next receive call will be asking for the version data */
326 KdpSendPacketHandler = NULL;
327 KdpManipulateStateHandler = GetVersionManipulateStateHandler;
328 return TRUE;
329 }
330
331 /* PUBLIC FUNCTIONS ***********************************************************/
332
333 /******************************************************************************
334 * \name KdReceivePacket
335 * \brief Receive a packet from the KD port.
336 * \param [in] PacketType Describes the type of the packet to receive.
337 * This can be one of the PACKET_TYPE_ constants.
338 * \param [out] MessageHeader Pointer to a STRING structure for the header.
339 * \param [out] MessageData Pointer to a STRING structure for the data.
340 * \return KdPacketReceived if successful, KdPacketTimedOut if the receive
341 * timed out, KdPacketNeedsResend to signal that the last packet needs
342 * to be sent again.
343 * \note If PacketType is PACKET_TYPE_KD_POLL_BREAKIN, the function doesn't
344 * wait for any data, but returns KdPacketTimedOut instantly if no breakin
345 * packet byte is received.
346 * \sa http://www.nynaeve.net/?p=169
347 */
348 KDSTATUS
349 NTAPI
KdReceivePacket(_In_ ULONG PacketType,_Out_ PSTRING MessageHeader,_Out_ PSTRING MessageData,_Out_ PULONG DataLength,_Inout_ PKD_CONTEXT KdContext)350 KdReceivePacket(
351 _In_ ULONG PacketType,
352 _Out_ PSTRING MessageHeader,
353 _Out_ PSTRING MessageData,
354 _Out_ PULONG DataLength,
355 _Inout_ PKD_CONTEXT KdContext)
356 {
357 KDDBGPRINT("KdReceivePacket --> ");
358
359 if (PacketType == PACKET_TYPE_KD_POLL_BREAKIN)
360 {
361 static BOOLEAN firstTime = TRUE;
362 KDDBGPRINT("Polling break in.\n");
363 if (firstTime)
364 {
365 /* Force debug break on init */
366 firstTime = FALSE;
367 return KdPacketReceived;
368 }
369
370 return KdpPollBreakIn();
371 }
372
373 if (PacketType == PACKET_TYPE_KD_DEBUG_IO)
374 {
375 static BOOLEAN ignore = 0;
376 KDDBGPRINT("Debug prompt.\n");
377 /* HACK ! Debug prompt asks for break or ignore. First break, then ignore. */
378 MessageData->Length = 1;
379 MessageData->Buffer[0] = ignore ? 'i' : 'b';
380 ignore = !ignore;
381 return KdPacketReceived;
382 }
383
384 if (PacketType == PACKET_TYPE_KD_STATE_MANIPULATE)
385 {
386 DBGKD_MANIPULATE_STATE64* State = (DBGKD_MANIPULATE_STATE64*)MessageHeader->Buffer;
387
388 KDDBGPRINT("State manipulation: ");
389
390 /* Maybe we are in a send<->receive loop that GDB doesn't need to know about */
391 if (KdpManipulateStateHandler != NULL)
392 {
393 KDDBGPRINT("We have a manipulate state handler.\n");
394 return KdpManipulateStateHandler(State, MessageData, DataLength, KdContext);
395 }
396
397 /* Receive data from GDB and interpret it */
398 KDDBGPRINT("Receiving data from GDB.\n");
399 return gdb_receive_and_interpret_packet(State, MessageData, DataLength, KdContext);
400 }
401
402 /* What should we do ? */
403 while (1);
404 return KdPacketNeedsResend;
405 }
406
407 VOID
408 NTAPI
KdSendPacket(IN ULONG PacketType,IN PSTRING MessageHeader,IN PSTRING MessageData,IN OUT PKD_CONTEXT KdContext)409 KdSendPacket(
410 IN ULONG PacketType,
411 IN PSTRING MessageHeader,
412 IN PSTRING MessageData,
413 IN OUT PKD_CONTEXT KdContext)
414 {
415 /* Override if we have some debug print from KD. */
416 if (PacketType == PACKET_TYPE_KD_DEBUG_IO)
417 {
418 send_kd_debug_io((DBGKD_DEBUG_IO*)MessageHeader->Buffer, MessageData);
419 return;
420 }
421
422 /* Maybe we are in a send <-> receive loop that GDB doesn't need to know about */
423 if (KdpSendPacketHandler
424 && KdpSendPacketHandler(PacketType, MessageHeader, MessageData))
425 {
426 return;
427 }
428
429 switch (PacketType)
430 {
431 case PACKET_TYPE_KD_STATE_CHANGE64:
432 send_kd_state_change((DBGKD_ANY_WAIT_STATE_CHANGE*)MessageHeader->Buffer);
433 return;
434 case PACKET_TYPE_KD_DEBUG_IO:
435 send_kd_debug_io((DBGKD_DEBUG_IO*)MessageHeader->Buffer, MessageData);
436 break;
437 case PACKET_TYPE_KD_STATE_MANIPULATE:
438 send_kd_state_manipulate((DBGKD_MANIPULATE_STATE64*)MessageHeader->Buffer, MessageData);
439 break;
440 default:
441 KDDBGPRINT("Unknown packet type %u.\n", PacketType);
442 while (1);
443 }
444 }
445
446 /* EOF */
447