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