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