[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 DbgKdReadVirtualMemoryApi:
104 /* Answer to 'm' GDB request */
105 send_gdb_memory(MessageData->Buffer, State->u.ReadMemory.ActualBytesRead);
106 break;
107 case DbgKdGetVersionApi:
108 {
109 LIST_ENTRY* DebuggerDataList;
110 /* Simply get a copy */
111 RtlCopyMemory(&KdVersion, &State->u.GetVersion64, sizeof(KdVersion));
112 DebuggerDataList = (LIST_ENTRY*)(ULONG_PTR)KdVersion.DebuggerDataList;
113 KdDebuggerDataBlock = CONTAINING_RECORD(DebuggerDataList->Flink, KDDEBUGGER_DATA64, Header.List);
114 return;
115 }
116 default:
117 /* FIXME */
118 while (1);
119 }
120 }
121
122 /* PUBLIC FUNCTIONS ***********************************************************/
123
124 /******************************************************************************
125 * \name KdReceivePacket
126 * \brief Receive a packet from the KD port.
127 * \param [in] PacketType Describes the type of the packet to receive.
128 * This can be one of the PACKET_TYPE_ constants.
129 * \param [out] MessageHeader Pointer to a STRING structure for the header.
130 * \param [out] MessageData Pointer to a STRING structure for the data.
131 * \return KdPacketReceived if successful, KdPacketTimedOut if the receive
132 * timed out, KdPacketNeedsResend to signal that the last packet needs
133 * to be sent again.
134 * \note If PacketType is PACKET_TYPE_KD_POLL_BREAKIN, the function doesn't
135 * wait for any data, but returns KdPacketTimedOut instantly if no breakin
136 * packet byte is received.
137 * \sa http://www.nynaeve.net/?p=169
138 */
139 KDSTATUS
140 NTAPI
141 KdReceivePacket(
142 _In_ ULONG PacketType,
143 _Out_ PSTRING MessageHeader,
144 _Out_ PSTRING MessageData,
145 _Out_ PULONG DataLength,
146 _Inout_ PKD_CONTEXT KdContext)
147 {
148 KDSTATUS Status;
149 DBGKD_MANIPULATE_STATE64* State;
150
151 /* Special handling for breakin packet */
152 if (PacketType == PACKET_TYPE_KD_POLL_BREAKIN)
153 {
154 return KdpPollBreakIn();
155 }
156
157 if (PacketType != PACKET_TYPE_KD_STATE_MANIPULATE)
158 {
159 /* What should we do ? */
160 while (1);
161 }
162
163 State = (DBGKD_MANIPULATE_STATE64*)MessageHeader->Buffer;
164
165 /* Maybe we are in a send<->receive loop that GDB doesn't need to know about */
166 if (KdpManipulateStateHandler != NULL)
167 return KdpManipulateStateHandler(State, MessageData, DataLength, KdContext);
168
169 if (FakeNextManipulatePacket)
170 {
171 FakeNextManipulatePacket = FALSE;
172 *State = FakeManipulateState;
173 return KdPacketReceived;
174 }
175
176 /* Receive data from GDB */
177 Status = gdb_receive_packet(KdContext);
178 if (Status != KdPacketReceived)
179 return Status;
180
181 /* Interpret it */
182 return gdb_interpret_input(State, MessageData, DataLength, KdContext);
183 }
184
185 VOID
186 NTAPI
187 KdSendPacket(
188 IN ULONG PacketType,
189 IN PSTRING MessageHeader,
190 IN PSTRING MessageData,
191 IN OUT PKD_CONTEXT KdContext)
192 {
193 /* Maybe we are in a send <-> receive loop that GDB doesn't need to know about */
194 if (KdpSendPacketHandler)
195 {
196 KdpSendPacketHandler(PacketType, MessageHeader, MessageData);
197 return;
198 }
199
200 switch (PacketType)
201 {
202 case PACKET_TYPE_KD_STATE_CHANGE64:
203 send_kd_state_change((DBGKD_ANY_WAIT_STATE_CHANGE*)MessageHeader->Buffer);
204 return;
205 case PACKET_TYPE_KD_DEBUG_IO:
206 send_kd_debug_io((DBGKD_DEBUG_IO*)MessageHeader->Buffer, MessageData);
207 break;
208 case PACKET_TYPE_KD_STATE_MANIPULATE:
209 send_kd_state_manipulate((DBGKD_MANIPULATE_STATE64*)MessageHeader->Buffer, MessageData);
210 break;
211 default:
212 /* FIXME */
213 while (1);
214 }
215 }
216
217 /* EOF */