[KDGDB]
[reactos.git] / reactos / drivers / base / kdgdb / kdpacket.c
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
18 /* GLOBALS ********************************************************************/
19 DBGKD_GET_VERSION64 KdVersion;
20 KDDEBUGGER_DATA64* KdDebuggerDataBlock;
21 BOOLEAN InException = FALSE;
22 /* Callbacks used to communicate with KD aside from GDB */
23 KDP_SEND_HANDLER KdpSendPacketHandler = FirstSendHandler;
24 KDP_MANIPULATESTATE_HANDLER KdpManipulateStateHandler = NULL;
25 /* Data describing the current exception */
26 DBGKD_ANY_WAIT_STATE_CHANGE CurrentStateChange;
27 CONTEXT CurrentContext;
28
29 /* PRIVATE FUNCTIONS **********************************************************/
30
31 static
32 VOID
33 GetContextSendHandler(
34 _In_ ULONG PacketType,
35 _In_ PSTRING MessageHeader,
36 _In_ PSTRING MessageData
37 )
38 {
39 DBGKD_MANIPULATE_STATE64* State = (DBGKD_MANIPULATE_STATE64*)MessageHeader->Buffer;
40 const CONTEXT* Context = (const CONTEXT*)MessageData->Buffer;
41
42 if ((PacketType != PACKET_TYPE_KD_STATE_MANIPULATE)
43 || (State->ApiNumber != DbgKdGetContextApi)
44 || (MessageData->Length < sizeof(*Context)))
45 {
46 /* Should we bugcheck ? */
47 KDDBGPRINT("ERROR: Received wrong packet from KD.\n");
48 while (1);
49 }
50
51 /* Just copy it */
52 RtlCopyMemory(&CurrentContext, Context, sizeof(*Context));
53 KdpSendPacketHandler = NULL;
54 }
55
56 static
57 KDSTATUS
58 GetContextManipulateHandler(
59 _Out_ DBGKD_MANIPULATE_STATE64* State,
60 _Out_ PSTRING MessageData,
61 _Out_ PULONG MessageLength,
62 _Inout_ PKD_CONTEXT KdContext
63 )
64 {
65 State->ApiNumber = DbgKdGetContextApi;
66 State->Processor = CurrentStateChange.Processor;
67 State->ReturnStatus = STATUS_SUCCESS;
68 State->ProcessorLevel = CurrentStateChange.ProcessorLevel;
69 MessageData->Length = 0;
70
71 /* Update the send <-> receive loop handler */
72 KdpSendPacketHandler = GetContextSendHandler;
73 KdpManipulateStateHandler = NULL;
74
75 return KdPacketReceived;
76 }
77
78 static
79 VOID
80 SetContextSendHandler(
81 _In_ ULONG PacketType,
82 _In_ PSTRING MessageHeader,
83 _In_ PSTRING MessageData
84 )
85 {
86 DBGKD_MANIPULATE_STATE64* State = (DBGKD_MANIPULATE_STATE64*)MessageHeader->Buffer;
87
88 /* We just confirm that all went well */
89 if ((PacketType != PACKET_TYPE_KD_STATE_MANIPULATE)
90 || (State->ApiNumber != DbgKdSetContextApi)
91 || (State->ReturnStatus != STATUS_SUCCESS))
92 {
93 /* Should we bugcheck ? */
94 while (1);
95 }
96
97 KdpSendPacketHandler = NULL;
98 }
99
100 KDSTATUS
101 SetContextManipulateHandler(
102 _Out_ DBGKD_MANIPULATE_STATE64* State,
103 _Out_ PSTRING MessageData,
104 _Out_ PULONG MessageLength,
105 _Inout_ PKD_CONTEXT KdContext
106 )
107 {
108 State->ApiNumber = DbgKdSetContextApi;
109 State->Processor = CurrentStateChange.Processor;
110 State->ReturnStatus = STATUS_SUCCESS;
111 State->ProcessorLevel = CurrentStateChange.ProcessorLevel;
112 MessageData->Length = sizeof(CurrentContext);
113
114 if (MessageData->MaximumLength < sizeof(CurrentContext))
115 {
116 while (1);
117 }
118
119 RtlCopyMemory(MessageData->Buffer, &CurrentContext, sizeof(CurrentContext));
120
121 /* Update the send <-> receive loop handlers */
122 KdpSendPacketHandler = SetContextSendHandler;
123 KdpManipulateStateHandler = NULL;
124
125 return KdPacketReceived;
126 }
127
128 static
129 void
130 send_kd_state_change(DBGKD_ANY_WAIT_STATE_CHANGE* StateChange)
131 {
132 switch (StateChange->NewState)
133 {
134 case DbgKdLoadSymbolsStateChange:
135 {
136 /* We don't care about symbols loading */
137 KdpManipulateStateHandler = ContinueManipulateStateHandler;
138 break;
139 }
140 case DbgKdExceptionStateChange:
141 /* Save current state for later GDB queries */
142 CurrentStateChange = *StateChange;
143 /* Unless GDB tells us otherwise, those are what we should have */
144 gdb_dbg_thread = PsGetThreadId((PETHREAD)StateChange->Thread);
145 gdb_dbg_process = PsGetThreadProcessId((PETHREAD)StateChange->Thread);
146 gdb_send_exception();
147 /* Next receive call will ask for the context */
148 KdpManipulateStateHandler = GetContextManipulateHandler;
149 break;
150 default:
151 /* FIXME */
152 while (1);
153 }
154 }
155
156 static
157 void
158 send_kd_debug_io(
159 _In_ DBGKD_DEBUG_IO* DebugIO,
160 _In_ PSTRING String)
161 {
162 switch (DebugIO->ApiNumber)
163 {
164 case DbgKdPrintStringApi:
165 gdb_send_debug_io(String);
166 break;
167 default:
168 /* FIXME */
169 while (1);
170 }
171 }
172
173 static
174 void
175 send_kd_state_manipulate(
176 _In_ DBGKD_MANIPULATE_STATE64* State,
177 _In_ PSTRING MessageData)
178 {
179 switch (State->ApiNumber)
180 {
181 #if 0
182 case DbgKdGetContextApi:
183 /* This is an answer to a 'g' GDB request */
184 gdb_send_registers((CONTEXT*)MessageData->Buffer);
185 return;
186 #endif
187 default:
188 /* FIXME */
189 while (1);
190 }
191 }
192
193 KDSTATUS
194 ContinueManipulateStateHandler(
195 _Out_ DBGKD_MANIPULATE_STATE64* State,
196 _Out_ PSTRING MessageData,
197 _Out_ PULONG MessageLength,
198 _Inout_ PKD_CONTEXT KdContext
199 )
200 {
201 /* Let's go on */
202 State->ApiNumber = DbgKdContinueApi;
203 State->ReturnStatus = STATUS_SUCCESS; /* ? */
204 State->Processor = CurrentStateChange.Processor;
205 State->ProcessorLevel = CurrentStateChange.ProcessorLevel;
206 if (MessageData)
207 MessageData->Length = 0;
208 *MessageLength = 0;
209 State->u.Continue.ContinueStatus = STATUS_SUCCESS;
210
211 /* We definitely are at the end of the send <-> receive loop, if any */
212 KdpSendPacketHandler = NULL;
213 KdpManipulateStateHandler = NULL;
214 return KdPacketReceived;
215 }
216
217 static
218 VOID
219 GetVersionSendHandler(
220 _In_ ULONG PacketType,
221 _In_ PSTRING MessageHeader,
222 _In_ PSTRING MessageData)
223 {
224 DBGKD_MANIPULATE_STATE64* State = (DBGKD_MANIPULATE_STATE64*)MessageHeader->Buffer;
225 LIST_ENTRY* DebuggerDataList;
226
227 /* Confirm that all went well */
228 if ((PacketType != PACKET_TYPE_KD_STATE_MANIPULATE)
229 || (State->ApiNumber != DbgKdGetVersionApi)
230 || !NT_SUCCESS(State->ReturnStatus))
231 {
232 /* FIXME: should detach from KD and go along without debugging */
233 KDDBGPRINT("Wrong packet received after asking for data.\n");
234 while(1);
235 }
236
237 /* Copy the relevant data */
238 RtlCopyMemory(&KdVersion, &State->u.GetVersion64, sizeof(KdVersion));
239 DebuggerDataList = (LIST_ENTRY*)(ULONG_PTR)KdVersion.DebuggerDataList;
240 KdDebuggerDataBlock = CONTAINING_RECORD(DebuggerDataList->Flink, KDDEBUGGER_DATA64, Header.List);
241
242 /* We can tell KD to continue */
243 KdpSendPacketHandler = NULL;
244 KdpManipulateStateHandler = ContinueManipulateStateHandler;
245 }
246
247 static
248 KDSTATUS
249 GetVersionManipulateStateHandler(
250 _Out_ DBGKD_MANIPULATE_STATE64* State,
251 _Out_ PSTRING MessageData,
252 _Out_ PULONG MessageLength,
253 _Inout_ PKD_CONTEXT KdContext)
254 {
255 /* Ask for the version data */
256 State->ApiNumber = DbgKdGetVersionApi;
257 State->Processor = CurrentStateChange.Processor;
258 State->ProcessorLevel = CurrentStateChange.ProcessorLevel;
259
260 /* The next send call will serve this query */
261 KdpSendPacketHandler = GetVersionSendHandler;
262 KdpManipulateStateHandler = NULL;
263
264 /* This will make KD breakin and we will be able to properly attach to GDB */
265 KdContext->KdpControlCPending = TRUE;
266
267 return KdPacketReceived;
268 }
269
270 static
271 VOID
272 FirstSendHandler(
273 _In_ ULONG PacketType,
274 _In_ PSTRING MessageHeader,
275 _In_ PSTRING MessageData)
276 {
277 DBGKD_ANY_WAIT_STATE_CHANGE* StateChange = (DBGKD_ANY_WAIT_STATE_CHANGE*)MessageHeader->Buffer;
278
279 if (PacketType == PACKET_TYPE_KD_DEBUG_IO)
280 {
281 /* This is not the packet we are waiting for */
282 send_kd_debug_io((DBGKD_DEBUG_IO*)MessageHeader->Buffer, MessageData);
283 return;
284 }
285
286 if (PacketType != PACKET_TYPE_KD_STATE_CHANGE64)
287 {
288 KDDBGPRINT("First KD packet is not a state change!\n");
289 /* FIXME: What should we send back to KD ? */
290 while(1);
291 }
292
293 CurrentStateChange = *StateChange;
294
295 /* The next receive call will be asking for the version data */
296 KdpSendPacketHandler = NULL;
297 KdpManipulateStateHandler = GetVersionManipulateStateHandler;
298 }
299
300 /* PUBLIC FUNCTIONS ***********************************************************/
301
302 /******************************************************************************
303 * \name KdReceivePacket
304 * \brief Receive a packet from the KD port.
305 * \param [in] PacketType Describes the type of the packet to receive.
306 * This can be one of the PACKET_TYPE_ constants.
307 * \param [out] MessageHeader Pointer to a STRING structure for the header.
308 * \param [out] MessageData Pointer to a STRING structure for the data.
309 * \return KdPacketReceived if successful, KdPacketTimedOut if the receive
310 * timed out, KdPacketNeedsResend to signal that the last packet needs
311 * to be sent again.
312 * \note If PacketType is PACKET_TYPE_KD_POLL_BREAKIN, the function doesn't
313 * wait for any data, but returns KdPacketTimedOut instantly if no breakin
314 * packet byte is received.
315 * \sa http://www.nynaeve.net/?p=169
316 */
317 KDSTATUS
318 NTAPI
319 KdReceivePacket(
320 _In_ ULONG PacketType,
321 _Out_ PSTRING MessageHeader,
322 _Out_ PSTRING MessageData,
323 _Out_ PULONG DataLength,
324 _Inout_ PKD_CONTEXT KdContext)
325 {
326 KDSTATUS Status;
327 DBGKD_MANIPULATE_STATE64* State;
328
329 /* Special handling for breakin packet */
330 if (PacketType == PACKET_TYPE_KD_POLL_BREAKIN)
331 {
332 return KdpPollBreakIn();
333 }
334
335 if (PacketType != PACKET_TYPE_KD_STATE_MANIPULATE)
336 {
337 /* What should we do ? */
338 while (1);
339 }
340
341 State = (DBGKD_MANIPULATE_STATE64*)MessageHeader->Buffer;
342
343 /* Maybe we are in a send<->receive loop that GDB doesn't need to know about */
344 if (KdpManipulateStateHandler != NULL)
345 return KdpManipulateStateHandler(State, MessageData, DataLength, KdContext);
346
347 /* Receive data from GDB */
348 Status = gdb_receive_packet(KdContext);
349 if (Status != KdPacketReceived)
350 return Status;
351
352 /* Interpret it */
353 return gdb_interpret_input(State, MessageData, DataLength, KdContext);
354 }
355
356 VOID
357 NTAPI
358 KdSendPacket(
359 IN ULONG PacketType,
360 IN PSTRING MessageHeader,
361 IN PSTRING MessageData,
362 IN OUT PKD_CONTEXT KdContext)
363 {
364 /* Maybe we are in a send <-> receive loop that GDB doesn't need to know about */
365 if (KdpSendPacketHandler)
366 {
367 KdpSendPacketHandler(PacketType, MessageHeader, MessageData);
368 return;
369 }
370
371 switch (PacketType)
372 {
373 case PACKET_TYPE_KD_STATE_CHANGE64:
374 send_kd_state_change((DBGKD_ANY_WAIT_STATE_CHANGE*)MessageHeader->Buffer);
375 return;
376 case PACKET_TYPE_KD_DEBUG_IO:
377 send_kd_debug_io((DBGKD_DEBUG_IO*)MessageHeader->Buffer, MessageData);
378 break;
379 case PACKET_TYPE_KD_STATE_MANIPULATE:
380 send_kd_state_manipulate((DBGKD_MANIPULATE_STATE64*)MessageHeader->Buffer, MessageData);
381 break;
382 default:
383 /* FIXME */
384 while (1);
385 }
386 }
387
388 /* EOF */