ReactOS  0.4.14-dev-342-gdc047f9
kddll.c
Go to the documentation of this file.
1 /*
2  * COPYRIGHT: GPL, see COPYING in the top level directory
3  * PROJECT: ReactOS kernel
4  * FILE: drivers/base/kddll/kddll.c
5  * PURPOSE: Base functions for the kernel debugger.
6  * PROGRAMMER: Timo Kreuzer (timo.kreuzer@reactos.org)
7  */
8 
9 #include "kddll.h"
10 
11 /* GLOBALS ********************************************************************/
12 
15 
16 
17 /* PRIVATE FUNCTIONS **********************************************************/
18 
19 /******************************************************************************
20  * \name KdpCalculateChecksum
21  * \brief Calculates the checksum for the packet data.
22  * \param Buffer Pointer to the packet data.
23  * \param Length Length of data in bytes.
24  * \return The calculated checksum.
25  * \sa http://www.vista-xp.co.uk/forums/technical-reference-library/2540-basics-debugging.html
26  */
27 ULONG
28 NTAPI
30  IN PVOID Buffer,
31  IN ULONG Length)
32 {
33  PUCHAR ByteBuffer = Buffer;
34  ULONG Checksum = 0;
35 
36  while (Length-- > 0)
37  {
38  Checksum += (ULONG)*ByteBuffer++;
39  }
40  return Checksum;
41 }
42 
43 VOID
44 NTAPI
46  IN USHORT PacketType,
47  IN ULONG PacketId OPTIONAL)
48 {
50 
51  Packet.PacketLeader = CONTROL_PACKET_LEADER;
52  Packet.PacketId = PacketId;
53  Packet.ByteCount = 0;
54  Packet.Checksum = 0;
55  Packet.PacketType = PacketType;
56 
57  KdpSendBuffer(&Packet, sizeof(KD_PACKET));
58 }
59 
60 
61 /* PUBLIC FUNCTIONS ***********************************************************/
62 
63 /******************************************************************************
64  * \name KdReceivePacket
65  * \brief Receive a packet from the KD port.
66  * \param [in] PacketType Describes the type of the packet to receive.
67  * This can be one of the PACKET_TYPE_ constants.
68  * \param [out] MessageHeader Pointer to a STRING structure for the header.
69  * \param [out] MessageData Pointer to a STRING structure for the data.
70  * \return KdPacketReceived if successful, KdPacketTimedOut if the receive
71  * timed out, KdPacketNeedsResend to signal that the last packet needs
72  * to be sent again.
73  * \note If PacketType is PACKET_TYPE_KD_POLL_BREAKIN, the function doesn't
74  * wait for any data, but returns KdPacketTimedOut instantly if no breakin
75  * packet byte is received.
76  * \sa http://www.nynaeve.net/?p=169
77  */
79 NTAPI
81  IN ULONG PacketType,
82  OUT PSTRING MessageHeader,
83  OUT PSTRING MessageData,
85  IN OUT PKD_CONTEXT KdContext)
86 {
87  UCHAR Byte = 0;
88  KDP_STATUS KdStatus;
90  ULONG Checksum;
91 
92  /* Special handling for breakin packet */
93  if (PacketType == PACKET_TYPE_KD_POLL_BREAKIN)
94  {
95  return KdpPollBreakIn();
96  }
97 
98  for (;;)
99  {
100  /* Step 1 - Read PacketLeader */
101  KdStatus = KdpReceivePacketLeader(&Packet.PacketLeader);
102  if (KdStatus != KDP_PACKET_RECEIVED)
103  {
104  /* Check if we got a breakin */
105  if (KdStatus == KDP_PACKET_RESEND)
106  {
107  KdContext->KdpControlCPending = TRUE;
108  }
109  return KdStatus;
110  }
111 
112  /* Step 2 - Read PacketType */
113  KdStatus = KdpReceiveBuffer(&Packet.PacketType, sizeof(USHORT));
114  if (KdStatus != KDP_PACKET_RECEIVED)
115  {
116  /* Didn't receive a PacketType. */
117  return KdStatus;
118  }
119 
120  /* Check if we got a resend packet */
121  if (Packet.PacketLeader == CONTROL_PACKET_LEADER &&
122  Packet.PacketType == PACKET_TYPE_KD_RESEND)
123  {
124  return KDP_PACKET_RESEND;
125  }
126 
127  /* Step 3 - Read ByteCount */
128  KdStatus = KdpReceiveBuffer(&Packet.ByteCount, sizeof(USHORT));
129  if (KdStatus != KDP_PACKET_RECEIVED)
130  {
131  /* Didn't receive ByteCount. */
132  return KdStatus;
133  }
134 
135  /* Step 4 - Read PacketId */
136  KdStatus = KdpReceiveBuffer(&Packet.PacketId, sizeof(ULONG));
137  if (KdStatus != KDP_PACKET_RECEIVED)
138  {
139  /* Didn't receive PacketId. */
140  return KdStatus;
141  }
142 
143 /*
144  if (Packet.PacketId != ExpectedPacketId)
145  {
146  // Ask for a resend!
147  continue;
148  }
149 */
150 
151  /* Step 5 - Read Checksum */
152  KdStatus = KdpReceiveBuffer(&Packet.Checksum, sizeof(ULONG));
153  if (KdStatus != KDP_PACKET_RECEIVED)
154  {
155  /* Didn't receive Checksum. */
156  return KdStatus;
157  }
158 
159  /* Step 6 - Handle control packets */
160  if (Packet.PacketLeader == CONTROL_PACKET_LEADER)
161  {
162  switch (Packet.PacketType)
163  {
165  /* Are we waiting for an ACK packet? */
166  if (PacketType == PACKET_TYPE_KD_ACKNOWLEDGE &&
167  Packet.PacketId == (CurrentPacketId & ~SYNC_PACKET_ID))
168  {
169  /* Remote acknowledges the last packet */
170  CurrentPacketId ^= 1;
171  return KDP_PACKET_RECEIVED;
172  }
173  /* That's not what we were waiting for, start over */
174  continue;
175 
177  KDDBGPRINT("KdReceivePacket - got PACKET_TYPE_KD_RESET\n");
181  /* Fall through */
182 
184  KDDBGPRINT("KdReceivePacket - got PACKET_TYPE_KD_RESEND\n");
185  /* Remote wants us to resend the last packet */
186  return KDP_PACKET_RESEND;
187 
188  default:
189  KDDBGPRINT("KdReceivePacket - got unknown control packet\n");
190  /* We got an invalid packet, ignore it and start over */
191  continue;
192  }
193  }
194 
195  /* Did we wait for an ack packet? */
196  if (PacketType == PACKET_TYPE_KD_ACKNOWLEDGE)
197  {
198  /* We received something different */
200  CurrentPacketId ^= 1;
201  return KDP_PACKET_RECEIVED;
202  }
203 
204  /* Get size of the message header */
205  MessageHeader->Length = MessageHeader->MaximumLength;
206 
207  /* Packet smaller than expected or too big? */
208  if (Packet.ByteCount < MessageHeader->Length ||
209  Packet.ByteCount > PACKET_MAX_SIZE)
210  {
211  KDDBGPRINT("KdReceivePacket - too few data (%d) for type %d\n",
212  Packet.ByteCount, MessageHeader->Length);
213  MessageHeader->Length = Packet.ByteCount;
215  continue;
216  }
217 
218  //KDDBGPRINT("KdReceivePacket - got normal PacketType, Buffer = %p\n", MessageHeader->Buffer);
219 
220  /* Receive the message header data */
221  KdStatus = KdpReceiveBuffer(MessageHeader->Buffer,
222  MessageHeader->Length);
223  if (KdStatus != KDP_PACKET_RECEIVED)
224  {
225  /* Didn't receive data. Packet needs to be resent. */
226  KDDBGPRINT("KdReceivePacket - Didn't receive message header data.\n");
228  continue;
229  }
230 
231  //KDDBGPRINT("KdReceivePacket - got normal PacketType 3\n");
232 
233  /* Calculate checksum for the header data */
234  Checksum = KdpCalculateChecksum(MessageHeader->Buffer,
235  MessageHeader->Length);
236 
237  /* Calculate the length of the message data */
238  *DataLength = Packet.ByteCount - MessageHeader->Length;
239 
240  /* Shall we receive message data? */
241  if (MessageData)
242  {
243  /* Set the length of the message data */
244  MessageData->Length = (USHORT)*DataLength;
245 
246  /* Do we have data? */
247  if (MessageData->Length)
248  {
249  KDDBGPRINT("KdReceivePacket - got data\n");
250 
251  /* Receive the message data */
252  KdStatus = KdpReceiveBuffer(MessageData->Buffer,
253  MessageData->Length);
254  if (KdStatus != KDP_PACKET_RECEIVED)
255  {
256  /* Didn't receive data. Start over. */
257  KDDBGPRINT("KdReceivePacket - Didn't receive message data.\n");
259  continue;
260  }
261 
262  /* Add cheksum for message data */
263  Checksum += KdpCalculateChecksum(MessageData->Buffer,
264  MessageData->Length);
265  }
266  }
267 
268  /* We must receive a PACKET_TRAILING_BYTE now */
269  KdStatus = KdpReceiveBuffer(&Byte, sizeof(UCHAR));
270  if (KdStatus != KDP_PACKET_RECEIVED || Byte != PACKET_TRAILING_BYTE)
271  {
272  KDDBGPRINT("KdReceivePacket - wrong trailing byte (0x%x), status 0x%x\n", Byte, KdStatus);
274  continue;
275  }
276 
277  /* Compare checksum */
278  if (Packet.Checksum != Checksum)
279  {
280  KDDBGPRINT("KdReceivePacket - wrong cheksum, got %x, calculated %x\n",
281  Packet.Checksum, Checksum);
283  continue;
284  }
285 
286  /* Acknowledge the received packet */
288 
289  /* Check if the received PacketId is ok */
290  if (Packet.PacketId != RemotePacketId)
291  {
292  /* Continue with next packet */
293  continue;
294  }
295 
296  /* Did we get the right packet type? */
297  if (PacketType == Packet.PacketType)
298  {
299  /* Yes, return success */
300  //KDDBGPRINT("KdReceivePacket - all ok\n");
301  RemotePacketId ^= 1;
302  return KDP_PACKET_RECEIVED;
303  }
304 
305  /* We received something different, ignore it. */
306  KDDBGPRINT("KdReceivePacket - wrong PacketType\n");
307  }
308 
309  return KDP_PACKET_RECEIVED;
310 }
311 
312 VOID
313 NTAPI
315  IN ULONG PacketType,
316  IN PSTRING MessageHeader,
317  IN PSTRING MessageData,
318  IN OUT PKD_CONTEXT KdContext)
319 {
321  KDP_STATUS KdStatus;
322  ULONG Retries;
323 
324  /* Initialize a KD_PACKET */
325  Packet.PacketLeader = PACKET_LEADER;
326  Packet.PacketType = (USHORT)PacketType;
327  Packet.ByteCount = MessageHeader->Length;
328  Packet.Checksum = KdpCalculateChecksum(MessageHeader->Buffer,
329  MessageHeader->Length);
330 
331  /* If we have message data, add it to the packet */
332  if (MessageData)
333  {
334  Packet.ByteCount += MessageData->Length;
335  Packet.Checksum += KdpCalculateChecksum(MessageData->Buffer,
336  MessageData->Length);
337  }
338 
339  Retries = KdContext->KdpDefaultRetries;
340 
341  for (;;)
342  {
343  /* Set the packet id */
344  Packet.PacketId = CurrentPacketId;
345 
346  /* Send the packet header to the KD port */
347  KdpSendBuffer(&Packet, sizeof(KD_PACKET));
348 
349  /* Send the message header */
350  KdpSendBuffer(MessageHeader->Buffer, MessageHeader->Length);
351 
352  /* If we have message data, also send it */
353  if (MessageData)
354  {
355  KdpSendBuffer(MessageData->Buffer, MessageData->Length);
356  }
357 
358  /* Finalize with a trailing byte */
360 
361  /* Wait for acknowledge */
363  NULL,
364  NULL,
365  NULL,
366  KdContext);
367 
368  /* Did we succeed? */
369  if (KdStatus == KDP_PACKET_RECEIVED)
370  {
371  /* Packet received, we can quit the loop */
373  Retries = KdContext->KdpDefaultRetries;
374  break;
375  }
376  else if (KdStatus == KDP_PACKET_TIMEOUT)
377  {
378  /* Timeout, decrement the retry count */
379  if (Retries > 0)
380  Retries--;
381 
382  /*
383  * If the retry count reaches zero, bail out
384  * for packet types allowed to timeout.
385  */
386  if (Retries == 0)
387  {
388  ULONG MessageId = *(PULONG)MessageHeader->Buffer;
389  switch (PacketType)
390  {
392  {
393  if (MessageId != DbgKdPrintStringApi) continue;
394  break;
395  }
396 
399  {
400  if (MessageId != DbgKdLoadSymbolsStateChange) continue;
401  break;
402  }
403 
405  {
406  if (MessageId != DbgKdCreateFileApi) continue;
407  break;
408  }
409  }
410 
411  /* Reset debugger state */
413  SharedUserData->KdDebuggerEnabled &= ~0x00000002;
416 
417  return;
418  }
419  }
420  // else (KdStatus == KDP_PACKET_RESEND) /* Resend the packet */
421 
422  /* Packet timed out, send it again */
423  KDDBGPRINT("KdSendPacket got KdStatus 0x%x\n", KdStatus);
424  }
425 }
426 
427 /* EOF */
#define IN
Definition: typedefs.h:38
#define SYNC_PACKET_ID
Definition: windbgkd.h:25
#define TRUE
Definition: types.h:120
_In_ NDIS_HANDLE _In_ PNDIS_PACKET Packet
Definition: ndis.h:1548
VOID NTAPI KdpSendBuffer(IN PVOID Buffer, IN ULONG Size)
Definition: kdserial.c:21
#define INITIAL_PACKET_ID
Definition: windbgkd.h:24
#define KDDBGPRINT(...)
Definition: kddll.h:19
unsigned char Byte
Definition: zconf.h:391
KDP_STATUS
Definition: kddll.h:25
ULONG CurrentPacketId
Definition: kddll.c:13
unsigned char * PUCHAR
Definition: retypes.h:3
KDP_STATUS NTAPI KdReceivePacket(IN ULONG PacketType, OUT PSTRING MessageHeader, OUT PSTRING MessageData, OUT PULONG DataLength, IN OUT PKD_CONTEXT KdContext)
Definition: kddll.c:80
KDP_STATUS NTAPI KdpReceiveBuffer(OUT PVOID Buffer, IN ULONG Size)
Definition: kdserial.c:43
KDP_STATUS NTAPI KdpReceivePacketLeader(OUT PULONG PacketLeader)
Definition: kdserial.c:75
#define KD_DEBUGGER_NOT_PRESENT
Definition: kdfuncs.h:133
#define PACKET_MAX_SIZE
Definition: windbgkd.h:18
#define PACKET_TYPE_KD_ACKNOWLEDGE
Definition: windbgkd.h:45
NTSTATUS(* NTAPI)(IN PFILE_FULL_EA_INFORMATION EaBuffer, IN ULONG EaLength, OUT PULONG ErrorOffset)
Definition: IoEaTest.cpp:117
#define DbgKdPrintStringApi
Definition: windbgkd.h:122
KDP_STATUS NTAPI KdpPollBreakIn(VOID)
Definition: kdcom.c:332
#define PACKET_TYPE_KD_RESET
Definition: windbgkd.h:47
smooth NULL
Definition: ftsmooth.c:416
#define PACKET_TYPE_KD_FILE_IO
Definition: windbgkd.h:52
Definition: bufpool.h:45
switch(r->id)
Definition: btrfs.c:2904
#define PACKET_TRAILING_BYTE
Definition: windbgkd.h:36
ULONG NTAPI KdpCalculateChecksum(IN PVOID Buffer, IN ULONG Length)
Definition: kddll.c:29
#define DbgKdLoadSymbolsStateChange
Definition: windbgkd.h:60
#define PACKET_TYPE_KD_STATE_CHANGE32
Definition: windbgkd.h:42
VOID NTAPI KdpSendControlPacket(IN USHORT PacketType, IN ULONG PacketId OPTIONAL)
Definition: kddll.c:45
_In_ ULONG _In_ ULONG _In_ ULONG Length
Definition: ntddpcm.h:101
VOID NTAPI KdpSendByte(IN UCHAR Byte)
Definition: kdcom.c:280
#define SharedUserData
unsigned char UCHAR
Definition: xmlstorage.h:181
#define PACKET_TYPE_KD_STATE_CHANGE64
Definition: windbgkd.h:48
unsigned short USHORT
Definition: pedump.c:61
ULONG RemotePacketId
Definition: kddll.c:14
#define PACKET_TYPE_KD_DEBUG_IO
Definition: windbgkd.h:44
unsigned int * PULONG
Definition: retypes.h:1
#define PACKET_TYPE_KD_RESEND
Definition: windbgkd.h:46
#define OUT
Definition: typedefs.h:39
#define DbgKdCreateFileApi
Definition: windbgkd.h:139
unsigned int ULONG
Definition: retypes.h:1
_Must_inspect_result_ _Out_writes_to_ DataLength PHIDP_DATA _Inout_ PULONG DataLength
Definition: hidpi.h:333
IN BOOLEAN OUT PSTR Buffer
Definition: progress.h:34
VOID NTAPI KdSendPacket(IN ULONG PacketType, IN PSTRING MessageHeader, IN PSTRING MessageData, IN OUT PKD_CONTEXT KdContext)
Definition: kddll.c:314
#define PACKET_LEADER
Definition: windbgkd.h:32
#define CONTROL_PACKET_LEADER
Definition: windbgkd.h:34
#define PACKET_TYPE_KD_POLL_BREAKIN
Definition: windbgkd.h:49
PULONG MinorVersion OPTIONAL
Definition: CrossNt.h:68