xref: /reactos/drivers/base/kdgdb/kdpacket.c (revision 84344399)
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
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
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
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
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
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
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
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
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
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
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
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
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
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