[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 /* GLOBALS ********************************************************************/
11
12 DBGKD_ANY_WAIT_STATE_CHANGE CurrentStateChange;
13 DBGKD_GET_VERSION64 KdVersion;
14 KDDEBUGGER_DATA64* KdDebuggerDataBlock;
15 /* Callbacks used to communicate with KD aside from GDB */
16 KDP_SEND_HANDLER KdpSendPacketHandler = NULL;
17 KDP_MANIPULATESTATE_HANDLER KdpManipulateStateHandler = NULL;
18
19 /* LOCALS *********************************************************************/
20 static BOOLEAN FakeNextManipulatePacket = FALSE;
21 static DBGKD_MANIPULATE_STATE64 FakeManipulateState = {0};
22
23 /* PRIVATE FUNCTIONS **********************************************************/
24 static
25 void
26 send_kd_state_change(DBGKD_ANY_WAIT_STATE_CHANGE* StateChange)
27 {
28 static BOOLEAN first = TRUE;
29
30 /* Save current state for later GDB queries */
31 CurrentStateChange = *StateChange;
32
33 if (first)
34 {
35 /*
36 * This is the first packet we receive.
37 * We take this as an opportunity to connect with GDB and to
38 * get the KD version block
39 */
40 FakeNextManipulatePacket = TRUE;
41 FakeManipulateState.ApiNumber = DbgKdGetVersionApi;
42 FakeManipulateState.Processor = StateChange->Processor;
43 FakeManipulateState.ProcessorLevel = StateChange->ProcessorLevel;
44 FakeManipulateState.ReturnStatus = STATUS_SUCCESS;
45
46 first = FALSE;
47 return;
48 }
49
50 switch (StateChange->NewState)
51 {
52 case DbgKdLoadSymbolsStateChange:
53 {
54 /* We don't care about symbols loading */
55 FakeNextManipulatePacket = TRUE;
56 FakeManipulateState.ApiNumber = DbgKdContinueApi;
57 FakeManipulateState.Processor = StateChange->Processor;
58 FakeManipulateState.ProcessorLevel = StateChange->ProcessorLevel;
59 FakeManipulateState.ReturnStatus = STATUS_SUCCESS;
60 FakeManipulateState.u.Continue.ContinueStatus = STATUS_SUCCESS;
61 break;
62 }
63 case DbgKdExceptionStateChange:
64 gdb_send_exception();
65 break;
66 default:
67 /* FIXME */
68 while (1);
69 }
70 }
71
72 static
73 void
74 send_kd_debug_io(
75 _In_ DBGKD_DEBUG_IO* DebugIO,
76 _In_ PSTRING String)
77 {
78 switch (DebugIO->ApiNumber)
79 {
80 case DbgKdPrintStringApi:
81 gdb_send_debug_io(String);
82 break;
83 default:
84 /* FIXME */
85 while (1);
86 }
87 }
88
89 static
90 void
91 send_kd_state_manipulate(
92 _In_ DBGKD_MANIPULATE_STATE64* State,
93 _In_ PSTRING MessageData)
94 {
95 switch (State->ApiNumber)
96 {
97 #if 0
98 case DbgKdGetContextApi:
99 /* This is an answer to a 'g' GDB request */
100 gdb_send_registers((CONTEXT*)MessageData->Buffer);
101 return;
102 #endif
103 case DbgKdGetVersionApi:
104 {
105 LIST_ENTRY* DebuggerDataList;
106 /* Simply get a copy */
107 RtlCopyMemory(&KdVersion, &State->u.GetVersion64, sizeof(KdVersion));
108 DebuggerDataList = (LIST_ENTRY*)(ULONG_PTR)KdVersion.DebuggerDataList;
109 KdDebuggerDataBlock = CONTAINING_RECORD(DebuggerDataList->Flink, KDDEBUGGER_DATA64, Header.List);
110 return;
111 }
112 default:
113 /* FIXME */
114 while (1);
115 }
116 }
117
118 /* PUBLIC FUNCTIONS ***********************************************************/
119
120 /******************************************************************************
121 * \name KdReceivePacket
122 * \brief Receive a packet from the KD port.
123 * \param [in] PacketType Describes the type of the packet to receive.
124 * This can be one of the PACKET_TYPE_ constants.
125 * \param [out] MessageHeader Pointer to a STRING structure for the header.
126 * \param [out] MessageData Pointer to a STRING structure for the data.
127 * \return KdPacketReceived if successful, KdPacketTimedOut if the receive
128 * timed out, KdPacketNeedsResend to signal that the last packet needs
129 * to be sent again.
130 * \note If PacketType is PACKET_TYPE_KD_POLL_BREAKIN, the function doesn't
131 * wait for any data, but returns KdPacketTimedOut instantly if no breakin
132 * packet byte is received.
133 * \sa http://www.nynaeve.net/?p=169
134 */
135 KDSTATUS
136 NTAPI
137 KdReceivePacket(
138 _In_ ULONG PacketType,
139 _Out_ PSTRING MessageHeader,
140 _Out_ PSTRING MessageData,
141 _Out_ PULONG DataLength,
142 _Inout_ PKD_CONTEXT KdContext)
143 {
144 KDSTATUS Status;
145 DBGKD_MANIPULATE_STATE64* State;
146
147 /* Special handling for breakin packet */
148 if (PacketType == PACKET_TYPE_KD_POLL_BREAKIN)
149 {
150 return KdpPollBreakIn();
151 }
152
153 if (PacketType != PACKET_TYPE_KD_STATE_MANIPULATE)
154 {
155 /* What should we do ? */
156 while (1);
157 }
158
159 State = (DBGKD_MANIPULATE_STATE64*)MessageHeader->Buffer;
160
161 /* Maybe we are in a send<->receive loop that GDB doesn't need to know about */
162 if (KdpManipulateStateHandler != NULL)
163 return KdpManipulateStateHandler(State, MessageData, DataLength, KdContext);
164
165 if (FakeNextManipulatePacket)
166 {
167 FakeNextManipulatePacket = FALSE;
168 *State = FakeManipulateState;
169 return KdPacketReceived;
170 }
171
172 /* Receive data from GDB */
173 Status = gdb_receive_packet(KdContext);
174 if (Status != KdPacketReceived)
175 return Status;
176
177 /* Interpret it */
178 return gdb_interpret_input(State, MessageData, DataLength, KdContext);
179 }
180
181 VOID
182 NTAPI
183 KdSendPacket(
184 IN ULONG PacketType,
185 IN PSTRING MessageHeader,
186 IN PSTRING MessageData,
187 IN OUT PKD_CONTEXT KdContext)
188 {
189 /* Maybe we are in a send <-> receive loop that GDB doesn't need to know about */
190 if (KdpSendPacketHandler)
191 {
192 KdpSendPacketHandler(PacketType, MessageHeader, MessageData);
193 return;
194 }
195
196 switch (PacketType)
197 {
198 case PACKET_TYPE_KD_STATE_CHANGE64:
199 send_kd_state_change((DBGKD_ANY_WAIT_STATE_CHANGE*)MessageHeader->Buffer);
200 return;
201 case PACKET_TYPE_KD_DEBUG_IO:
202 send_kd_debug_io((DBGKD_DEBUG_IO*)MessageHeader->Buffer, MessageData);
203 break;
204 case PACKET_TYPE_KD_STATE_MANIPULATE:
205 send_kd_state_manipulate((DBGKD_MANIPULATE_STATE64*)MessageHeader->Buffer, MessageData);
206 break;
207 default:
208 /* FIXME */
209 while (1);
210 }
211 }
212
213 /* EOF */