[KDGDB]
[reactos.git] / reactos / drivers / base / kdgdb / gdb_input.c
1 /*
2 * COPYRIGHT: GPL, see COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: drivers/base/kddll/gdb_input.c
5 * PURPOSE: Base functions for the kernel debugger.
6 */
7
8 #include "kdgdb.h"
9
10 /* LOCALS *********************************************************************/
11 static HANDLE gdb_run_thread;
12 static HANDLE gdb_dbg_process;
13 HANDLE gdb_dbg_thread;
14
15 /* PRIVATE FUNCTIONS **********************************************************/
16 static
17 HANDLE
18 hex_to_thread(char* buffer)
19 {
20 ULONG_PTR ret = 0;
21 char hex;
22 while (*buffer)
23 {
24 hex = hex_value(*buffer++);
25 if (hex < 0)
26 return (HANDLE)ret;
27 ret <<= 4;
28 ret += hex;
29 }
30 return (HANDLE)ret;
31 }
32
33 static
34 ULONG64
35 hex_to_address(char* buffer)
36 {
37 ULONG64 ret = 0;
38 char hex;
39 while (*buffer)
40 {
41 hex = hex_value(*buffer++);
42 if (hex < 0)
43 return ret;
44 ret <<= 4;
45 ret += hex;
46 }
47 return ret;
48 }
49
50 /* H* packets */
51 static
52 void
53 handle_gdb_set_thread(void)
54 {
55 switch (gdb_input[1])
56 {
57 case 'c':
58 if (strcmp(&gdb_input[2], "-1") == 0)
59 gdb_run_thread = (HANDLE)-1;
60 else
61 gdb_run_thread = hex_to_thread(&gdb_input[2]);
62 send_gdb_packet("OK");
63 break;
64 case 'g':
65 if (strncmp(&gdb_input[2], "p-1", 3) == 0)
66 {
67 gdb_dbg_process = (HANDLE)-1;
68 gdb_dbg_thread = (HANDLE)-1;
69 }
70 else
71 {
72 char* ptr = strstr(gdb_input, ".") + 1;
73 gdb_dbg_process = hex_to_thread(&gdb_input[3]);
74 if (strncmp(ptr, "-1", 2) == 0)
75 gdb_dbg_thread = (HANDLE)-1;
76 else
77 gdb_dbg_thread = hex_to_thread(ptr);
78 }
79 send_gdb_packet("OK");
80 break;
81 default:
82 KDDBGPRINT("KDGBD: Unknown 'H' command: %s\n", gdb_input);
83 send_gdb_packet("");
84 }
85 }
86
87 static
88 void
89 handle_gdb_thread_alive(void)
90 {
91 char* ptr = strstr(gdb_input, ".") + 1;
92 CLIENT_ID ClientId;
93 PETHREAD Thread;
94 NTSTATUS Status;
95
96 ClientId.UniqueProcess = hex_to_thread(&gdb_input[2]);
97 ClientId.UniqueThread = hex_to_thread(ptr);
98
99 Status = PsLookupProcessThreadByCid(&ClientId, NULL, &Thread);
100
101 if (!NT_SUCCESS(Status))
102 {
103 /* Thread doesn't exist */
104 send_gdb_packet("E03");
105 return;
106 }
107
108 /* It's OK */
109 ObDereferenceObject(Thread);
110 send_gdb_packet("OK");
111 }
112
113 /* q* packets */
114 static
115 void
116 handle_gdb_query(void)
117 {
118 if (strncmp(gdb_input, "qSupported:", 11) == 0)
119 {
120 send_gdb_packet("PacketSize=4096;multiprocess+;");
121 return;
122 }
123
124 if (strncmp(gdb_input, "qAttached", 9) == 0)
125 {
126 /* Say yes: the remote server didn't create the process, ReactOS did! */
127 send_gdb_packet("0");
128 return;
129 }
130
131 if (strncmp(gdb_input, "qRcmd,", 6) == 0)
132 {
133 send_gdb_packet("OK");
134 return;
135 }
136
137 if (strcmp(gdb_input, "qC") == 0)
138 {
139 char gdb_out[64];
140 sprintf(gdb_out, "QC:p%p.%p;",
141 PsGetThreadProcessId((PETHREAD)(ULONG_PTR)CurrentStateChange.Thread),
142 PsGetThreadId((PETHREAD)(ULONG_PTR)CurrentStateChange.Thread));
143 send_gdb_packet(gdb_out);
144 return;
145 }
146
147 if (strncmp(gdb_input, "qTStatus", 8) == 0)
148 {
149 /* We don't support tracepoints. */
150 send_gdb_packet("T0");
151 return;
152 }
153
154 KDDBGPRINT("KDGDB: Unknown query: %s\n", gdb_input);
155 send_gdb_packet("");
156 }
157
158 #if 0
159 static
160 KDSTATUS
161 handle_gdb_registers(
162 _Out_ DBGKD_MANIPULATE_STATE64* State,
163 _Out_ PSTRING MessageData,
164 _Out_ PULONG MessageLength)
165 {
166 /*
167 if (gdb_dbg_thread)
168 KDDBGPRINT("Should get registers from other thread!\n");
169 */
170
171 State->ApiNumber = DbgKdGetContextApi;
172 State->ReturnStatus = STATUS_SUCCESS; /* ? */
173 State->Processor = CurrentStateChange.Processor;
174 State->ProcessorLevel = CurrentStateChange.ProcessorLevel;
175 if (MessageData)
176 MessageData->Length = 0;
177 *MessageLength = 0;
178 return KdPacketReceived;
179 }
180 #endif
181
182 static
183 KDSTATUS
184 handle_gdb_read_mem(
185 _Out_ DBGKD_MANIPULATE_STATE64* State,
186 _Out_ PSTRING MessageData,
187 _Out_ PULONG MessageLength)
188 {
189 State->ApiNumber = DbgKdReadVirtualMemoryApi;
190 State->ReturnStatus = STATUS_SUCCESS; /* ? */
191 State->Processor = CurrentStateChange.Processor;
192 State->ProcessorLevel = CurrentStateChange.ProcessorLevel;
193 if (MessageData)
194 MessageData->Length = 0;
195 *MessageLength = 0;
196
197 State->u.ReadMemory.TargetBaseAddress = hex_to_address(&gdb_input[1]);
198 State->u.ReadMemory.TransferCount = hex_to_address(strstr(&gdb_input[1], ",") + 1);
199 return KdPacketReceived;
200 }
201
202 static
203 KDSTATUS
204 handle_gdb_v(
205 _Out_ DBGKD_MANIPULATE_STATE64* State,
206 _Out_ PSTRING MessageData,
207 _Out_ PULONG MessageLength,
208 _Inout_ PKD_CONTEXT KdContext)
209 {
210 if (strncmp(gdb_input, "vCont", 5) == 0)
211 {
212 if (gdb_input[5] == '?')
213 {
214 KDSTATUS Status;
215 /* Report what we support */
216 send_gdb_packet("vCont;c;C;s;S");
217 Status = gdb_receive_packet(KdContext);
218 if (Status != KdPacketReceived)
219 return Status;
220 return gdb_interpret_input(State, MessageData, MessageLength, KdContext);
221 }
222
223 if (strcmp(gdb_input, "vCont;c") == 0)
224 {
225 /* Let's go on */
226 State->ApiNumber = DbgKdContinueApi;
227 State->ReturnStatus = STATUS_SUCCESS; /* ? */
228 State->Processor = CurrentStateChange.Processor;
229 State->ProcessorLevel = CurrentStateChange.ProcessorLevel;
230 if (MessageData)
231 MessageData->Length = 0;
232 *MessageLength = 0;
233 State->u.Continue.ContinueStatus = STATUS_SUCCESS;
234 /* Tell GDB we are fine */
235 send_gdb_packet("OK");
236 return KdPacketReceived;
237 }
238 }
239
240 return KdPacketReceived;
241 }
242
243 /* GLOBAL FUNCTIONS ***********************************************************/
244 KDSTATUS
245 gdb_interpret_input(
246 _Out_ DBGKD_MANIPULATE_STATE64* State,
247 _Out_ PSTRING MessageData,
248 _Out_ PULONG MessageLength,
249 _Inout_ PKD_CONTEXT KdContext)
250 {
251 KDSTATUS Status;
252 switch (gdb_input[0])
253 {
254 case '?':
255 /* Send the Status */
256 gdb_send_exception();
257 break;
258 case 'g':
259 gdb_send_registers();
260 break;
261 case 'H':
262 handle_gdb_set_thread();
263 break;
264 case 'm':
265 return handle_gdb_read_mem(State, MessageData, MessageLength);
266 case 'q':
267 handle_gdb_query();
268 break;
269 case 'T':
270 handle_gdb_thread_alive();
271 break;
272 case 'v':
273 return handle_gdb_v(State, MessageData, MessageLength, KdContext);
274 default:
275 /* We don't know how to handle this request. Maybe this is something for KD */
276 State->ReturnStatus = STATUS_NOT_SUPPORTED;
277 return KdPacketReceived;
278 }
279 /* Get the answer from GDB */
280 Status = gdb_receive_packet(KdContext);
281 if (Status != KdPacketReceived)
282 return Status;
283 /* Try interpreting this new packet */
284 return gdb_interpret_input(State, MessageData, MessageLength, KdContext);
285 }