mshtml/tests: Fix some test failures on IE8.
[wine.git] / programs / winedbg / gdbproxy.c
blob680caeabc8273b2d81cb20f384858307faf6b6d1
1 /*
2 * A Win32 based proxy implementing the GBD remote protocol
3 * This allows to debug Wine (and any "emulated" program) under
4 * Linux using GDB
6 * Copyright (c) Eric Pouech 2002-2004
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 /* Protocol specification can be found here:
24 * http://sources.redhat.com/gdb/onlinedocs/gdb_32.html
27 #include "config.h"
28 #include "wine/port.h"
30 #include <assert.h>
31 #include <errno.h>
32 #include <fcntl.h>
33 #include <signal.h>
34 #include <stdarg.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #ifdef HAVE_SYS_POLL_H
38 # include <sys/poll.h>
39 #endif
40 #ifdef HAVE_SYS_WAIT_H
41 # include <sys/wait.h>
42 #endif
43 #ifdef HAVE_SYS_SOCKET_H
44 # include <sys/socket.h>
45 #endif
46 #ifdef HAVE_NETINET_IN_H
47 # include <netinet/in.h>
48 #endif
49 #ifdef HAVE_NETINET_TCP_H
50 # include <netinet/tcp.h>
51 #endif
52 #ifdef HAVE_UNISTD_H
53 # include <unistd.h>
54 #endif
56 /* if we don't have poll support on this system
57 * we won't provide gdb proxy support here...
59 #ifdef HAVE_POLL
61 #include "debugger.h"
63 #include "windef.h"
64 #include "winbase.h"
65 #include "tlhelp32.h"
67 #define GDBPXY_TRC_LOWLEVEL 0x01
68 #define GDBPXY_TRC_PACKET 0x02
69 #define GDBPXY_TRC_COMMAND 0x04
70 #define GDBPXY_TRC_COMMAND_ERROR 0x08
71 #define GDBPXY_TRC_WIN32_EVENT 0x10
72 #define GDBPXY_TRC_WIN32_ERROR 0x20
73 #define GDBPXY_TRC_COMMAND_FIXME 0x80
75 struct gdb_ctx_Xpoint
77 enum be_xpoint_type type; /* -1 means free */
78 void* addr;
79 unsigned long val;
82 struct gdb_context
84 /* gdb information */
85 int sock;
86 /* incoming buffer */
87 char* in_buf;
88 int in_buf_alloc;
89 int in_len;
90 /* split into individual packet */
91 char* in_packet;
92 int in_packet_len;
93 /* outgoing buffer */
94 char* out_buf;
95 int out_buf_alloc;
96 int out_len;
97 int out_curr_packet;
98 /* generic GDB thread information */
99 struct dbg_thread* exec_thread; /* thread used in step & continue */
100 struct dbg_thread* other_thread; /* thread to be used in any other operation */
101 unsigned trace;
102 /* current Win32 trap env */
103 unsigned last_sig;
104 BOOL in_trap;
105 CONTEXT context;
106 /* Win32 information */
107 struct dbg_process* process;
108 #define NUM_XPOINT 32
109 struct gdb_ctx_Xpoint Xpoints[NUM_XPOINT];
110 /* Unix environment */
111 unsigned long wine_segs[3]; /* load addresses of the ELF wine exec segments (text, bss and data) */
114 static struct be_process_io be_process_gdbproxy_io =
116 NULL, /* we shouldn't use close_process() in gdbproxy */
117 ReadProcessMemory,
118 WriteProcessMemory
121 /* =============================================== *
122 * B A S I C M A N I P U L A T I O N S *
123 * =============================================== *
126 static inline int hex_from0(char ch)
128 if (ch >= '0' && ch <= '9') return ch - '0';
129 if (ch >= 'A' && ch <= 'F') return ch - 'A' + 10;
130 if (ch >= 'a' && ch <= 'f') return ch - 'a' + 10;
132 assert(0);
133 return 0;
136 static inline unsigned char hex_to0(int x)
138 assert(x >= 0 && x < 16);
139 return "0123456789abcdef"[x];
142 static int hex_to_int(const char* src, size_t len)
144 unsigned int returnval = 0;
145 while (len--)
147 returnval <<= 4;
148 returnval |= hex_from0(*src++);
150 return returnval;
153 static void hex_from(void* dst, const char* src, size_t len)
155 unsigned char *p = dst;
156 while (len--)
158 *p++ = (hex_from0(src[0]) << 4) | hex_from0(src[1]);
159 src += 2;
163 static void hex_to(char* dst, const void* src, size_t len)
165 const unsigned char *p = src;
166 while (len--)
168 *dst++ = hex_to0(*p >> 4);
169 *dst++ = hex_to0(*p & 0x0F);
170 p++;
174 static unsigned char checksum(const char* ptr, int len)
176 unsigned cksum = 0;
178 while (len-- > 0)
179 cksum += (unsigned char)*ptr++;
180 return cksum;
183 /* =============================================== *
184 * C P U H A N D L E R S *
185 * =============================================== *
188 #ifdef __i386__
189 static size_t cpu_register_map[] = {
190 FIELD_OFFSET(CONTEXT, Eax),
191 FIELD_OFFSET(CONTEXT, Ecx),
192 FIELD_OFFSET(CONTEXT, Edx),
193 FIELD_OFFSET(CONTEXT, Ebx),
194 FIELD_OFFSET(CONTEXT, Esp),
195 FIELD_OFFSET(CONTEXT, Ebp),
196 FIELD_OFFSET(CONTEXT, Esi),
197 FIELD_OFFSET(CONTEXT, Edi),
198 FIELD_OFFSET(CONTEXT, Eip),
199 FIELD_OFFSET(CONTEXT, EFlags),
200 FIELD_OFFSET(CONTEXT, SegCs),
201 FIELD_OFFSET(CONTEXT, SegSs),
202 FIELD_OFFSET(CONTEXT, SegDs),
203 FIELD_OFFSET(CONTEXT, SegEs),
204 FIELD_OFFSET(CONTEXT, SegFs),
205 FIELD_OFFSET(CONTEXT, SegGs),
207 #elif defined(__powerpc__)
208 static size_t cpu_register_map[] = {
209 FIELD_OFFSET(CONTEXT, Gpr0),
210 FIELD_OFFSET(CONTEXT, Gpr1),
211 FIELD_OFFSET(CONTEXT, Gpr2),
212 FIELD_OFFSET(CONTEXT, Gpr3),
213 FIELD_OFFSET(CONTEXT, Gpr4),
214 FIELD_OFFSET(CONTEXT, Gpr5),
215 FIELD_OFFSET(CONTEXT, Gpr6),
216 FIELD_OFFSET(CONTEXT, Gpr7),
217 FIELD_OFFSET(CONTEXT, Gpr8),
218 FIELD_OFFSET(CONTEXT, Gpr9),
219 FIELD_OFFSET(CONTEXT, Gpr10),
220 FIELD_OFFSET(CONTEXT, Gpr11),
221 FIELD_OFFSET(CONTEXT, Gpr12),
222 FIELD_OFFSET(CONTEXT, Gpr13),
223 FIELD_OFFSET(CONTEXT, Gpr14),
224 FIELD_OFFSET(CONTEXT, Gpr15),
225 FIELD_OFFSET(CONTEXT, Gpr16),
226 FIELD_OFFSET(CONTEXT, Gpr17),
227 FIELD_OFFSET(CONTEXT, Gpr18),
228 FIELD_OFFSET(CONTEXT, Gpr19),
229 FIELD_OFFSET(CONTEXT, Gpr20),
230 FIELD_OFFSET(CONTEXT, Gpr21),
231 FIELD_OFFSET(CONTEXT, Gpr22),
232 FIELD_OFFSET(CONTEXT, Gpr23),
233 FIELD_OFFSET(CONTEXT, Gpr24),
234 FIELD_OFFSET(CONTEXT, Gpr25),
235 FIELD_OFFSET(CONTEXT, Gpr26),
236 FIELD_OFFSET(CONTEXT, Gpr27),
237 FIELD_OFFSET(CONTEXT, Gpr28),
238 FIELD_OFFSET(CONTEXT, Gpr29),
239 FIELD_OFFSET(CONTEXT, Gpr30),
240 FIELD_OFFSET(CONTEXT, Gpr31),
241 FIELD_OFFSET(CONTEXT, Fpr0),
242 FIELD_OFFSET(CONTEXT, Fpr1),
243 FIELD_OFFSET(CONTEXT, Fpr2),
244 FIELD_OFFSET(CONTEXT, Fpr3),
245 FIELD_OFFSET(CONTEXT, Fpr4),
246 FIELD_OFFSET(CONTEXT, Fpr5),
247 FIELD_OFFSET(CONTEXT, Fpr6),
248 FIELD_OFFSET(CONTEXT, Fpr7),
249 FIELD_OFFSET(CONTEXT, Fpr8),
250 FIELD_OFFSET(CONTEXT, Fpr9),
251 FIELD_OFFSET(CONTEXT, Fpr10),
252 FIELD_OFFSET(CONTEXT, Fpr11),
253 FIELD_OFFSET(CONTEXT, Fpr12),
254 FIELD_OFFSET(CONTEXT, Fpr13),
255 FIELD_OFFSET(CONTEXT, Fpr14),
256 FIELD_OFFSET(CONTEXT, Fpr15),
257 FIELD_OFFSET(CONTEXT, Fpr16),
258 FIELD_OFFSET(CONTEXT, Fpr17),
259 FIELD_OFFSET(CONTEXT, Fpr18),
260 FIELD_OFFSET(CONTEXT, Fpr19),
261 FIELD_OFFSET(CONTEXT, Fpr20),
262 FIELD_OFFSET(CONTEXT, Fpr21),
263 FIELD_OFFSET(CONTEXT, Fpr22),
264 FIELD_OFFSET(CONTEXT, Fpr23),
265 FIELD_OFFSET(CONTEXT, Fpr24),
266 FIELD_OFFSET(CONTEXT, Fpr25),
267 FIELD_OFFSET(CONTEXT, Fpr26),
268 FIELD_OFFSET(CONTEXT, Fpr27),
269 FIELD_OFFSET(CONTEXT, Fpr28),
270 FIELD_OFFSET(CONTEXT, Fpr29),
271 FIELD_OFFSET(CONTEXT, Fpr30),
272 FIELD_OFFSET(CONTEXT, Fpr31),
274 FIELD_OFFSET(CONTEXT, Iar),
275 FIELD_OFFSET(CONTEXT, Msr),
276 FIELD_OFFSET(CONTEXT, Cr),
277 FIELD_OFFSET(CONTEXT, Lr),
278 FIELD_OFFSET(CONTEXT, Ctr),
279 FIELD_OFFSET(CONTEXT, Xer),
280 /* FIXME: MQ is missing? FIELD_OFFSET(CONTEXT, Mq), */
281 /* see gdb/nlm/ppc.c */
283 #elif defined(__ALPHA__)
284 static size_t cpu_register_map[] = {
285 FIELD_OFFSET(CONTEXT, IntV0),
286 FIELD_OFFSET(CONTEXT, IntT0),
287 FIELD_OFFSET(CONTEXT, IntT1),
288 FIELD_OFFSET(CONTEXT, IntT2),
289 FIELD_OFFSET(CONTEXT, IntT3),
290 FIELD_OFFSET(CONTEXT, IntT4),
291 FIELD_OFFSET(CONTEXT, IntT5),
292 FIELD_OFFSET(CONTEXT, IntT6),
293 FIELD_OFFSET(CONTEXT, IntT7),
294 FIELD_OFFSET(CONTEXT, IntS0),
295 FIELD_OFFSET(CONTEXT, IntS1),
296 FIELD_OFFSET(CONTEXT, IntS2),
297 FIELD_OFFSET(CONTEXT, IntS3),
298 FIELD_OFFSET(CONTEXT, IntS4),
299 FIELD_OFFSET(CONTEXT, IntS5),
300 FIELD_OFFSET(CONTEXT, IntFp),
301 FIELD_OFFSET(CONTEXT, IntA0),
302 FIELD_OFFSET(CONTEXT, IntA1),
303 FIELD_OFFSET(CONTEXT, IntA2),
304 FIELD_OFFSET(CONTEXT, IntA3),
305 FIELD_OFFSET(CONTEXT, IntA4),
306 FIELD_OFFSET(CONTEXT, IntA5),
307 FIELD_OFFSET(CONTEXT, IntT8),
308 FIELD_OFFSET(CONTEXT, IntT9),
309 FIELD_OFFSET(CONTEXT, IntT10),
310 FIELD_OFFSET(CONTEXT, IntT11),
311 FIELD_OFFSET(CONTEXT, IntRa),
312 FIELD_OFFSET(CONTEXT, IntT12),
313 FIELD_OFFSET(CONTEXT, IntAt),
314 FIELD_OFFSET(CONTEXT, IntGp),
315 FIELD_OFFSET(CONTEXT, IntSp),
316 FIELD_OFFSET(CONTEXT, IntZero),
317 FIELD_OFFSET(CONTEXT, FltF0),
318 FIELD_OFFSET(CONTEXT, FltF1),
319 FIELD_OFFSET(CONTEXT, FltF2),
320 FIELD_OFFSET(CONTEXT, FltF3),
321 FIELD_OFFSET(CONTEXT, FltF4),
322 FIELD_OFFSET(CONTEXT, FltF5),
323 FIELD_OFFSET(CONTEXT, FltF6),
324 FIELD_OFFSET(CONTEXT, FltF7),
325 FIELD_OFFSET(CONTEXT, FltF8),
326 FIELD_OFFSET(CONTEXT, FltF9),
327 FIELD_OFFSET(CONTEXT, FltF10),
328 FIELD_OFFSET(CONTEXT, FltF11),
329 FIELD_OFFSET(CONTEXT, FltF12),
330 FIELD_OFFSET(CONTEXT, FltF13),
331 FIELD_OFFSET(CONTEXT, FltF14),
332 FIELD_OFFSET(CONTEXT, FltF15),
333 FIELD_OFFSET(CONTEXT, FltF16),
334 FIELD_OFFSET(CONTEXT, FltF17),
335 FIELD_OFFSET(CONTEXT, FltF18),
336 FIELD_OFFSET(CONTEXT, FltF19),
337 FIELD_OFFSET(CONTEXT, FltF20),
338 FIELD_OFFSET(CONTEXT, FltF21),
339 FIELD_OFFSET(CONTEXT, FltF22),
340 FIELD_OFFSET(CONTEXT, FltF23),
341 FIELD_OFFSET(CONTEXT, FltF24),
342 FIELD_OFFSET(CONTEXT, FltF25),
343 FIELD_OFFSET(CONTEXT, FltF26),
344 FIELD_OFFSET(CONTEXT, FltF27),
345 FIELD_OFFSET(CONTEXT, FltF28),
346 FIELD_OFFSET(CONTEXT, FltF29),
347 FIELD_OFFSET(CONTEXT, FltF30),
348 FIELD_OFFSET(CONTEXT, FltF31),
350 /* FIXME: Didn't look for the right order yet */
351 FIELD_OFFSET(CONTEXT, Fir),
352 FIELD_OFFSET(CONTEXT, Fpcr),
353 FIELD_OFFSET(CONTEXT, SoftFpcr),
355 #elif defined(__x86_64__)
356 static size_t cpu_register_map[] = {
357 FIELD_OFFSET(CONTEXT, Rax),
358 FIELD_OFFSET(CONTEXT, Rbx),
359 FIELD_OFFSET(CONTEXT, Rcx),
360 FIELD_OFFSET(CONTEXT, Rdx),
361 FIELD_OFFSET(CONTEXT, Rsi),
362 FIELD_OFFSET(CONTEXT, Rdi),
363 FIELD_OFFSET(CONTEXT, Rbp),
364 FIELD_OFFSET(CONTEXT, Rsp),
365 FIELD_OFFSET(CONTEXT, R8),
366 FIELD_OFFSET(CONTEXT, R9),
367 FIELD_OFFSET(CONTEXT, R10),
368 FIELD_OFFSET(CONTEXT, R11),
369 FIELD_OFFSET(CONTEXT, R12),
370 FIELD_OFFSET(CONTEXT, R13),
371 FIELD_OFFSET(CONTEXT, R14),
372 FIELD_OFFSET(CONTEXT, R15),
373 FIELD_OFFSET(CONTEXT, Rip),
374 FIELD_OFFSET(CONTEXT, EFlags),
375 FIELD_OFFSET(CONTEXT, SegCs),
376 FIELD_OFFSET(CONTEXT, SegSs),
377 FIELD_OFFSET(CONTEXT, SegDs),
378 FIELD_OFFSET(CONTEXT, SegEs),
379 FIELD_OFFSET(CONTEXT, SegFs),
380 FIELD_OFFSET(CONTEXT, SegGs),
382 #else
383 # error Define the registers map for your CPU
384 #endif
386 static const size_t cpu_num_regs = (sizeof(cpu_register_map) / sizeof(cpu_register_map[0]));
388 static inline unsigned long* cpu_register(CONTEXT* ctx, unsigned idx)
390 assert(idx < cpu_num_regs);
391 return (unsigned long*)((char*)ctx + cpu_register_map[idx]);
394 /* =============================================== *
395 * W I N 3 2 D E B U G I N T E R F A C E *
396 * =============================================== *
399 static BOOL fetch_context(struct gdb_context* gdbctx, HANDLE h, CONTEXT* ctx)
401 ctx->ContextFlags = CONTEXT_CONTROL
402 | CONTEXT_INTEGER
403 #ifdef CONTEXT_SEGMENTS
404 | CONTEXT_SEGMENTS
405 #endif
406 #ifdef CONTEXT_DEBUG_REGISTERS
407 | CONTEXT_DEBUG_REGISTERS
408 #endif
410 if (!GetThreadContext(h, ctx))
412 if (gdbctx->trace & GDBPXY_TRC_WIN32_ERROR)
413 fprintf(stderr, "Can't get thread's context\n");
414 return FALSE;
416 return TRUE;
419 static BOOL handle_exception(struct gdb_context* gdbctx, EXCEPTION_DEBUG_INFO* exc)
421 EXCEPTION_RECORD* rec = &exc->ExceptionRecord;
422 BOOL ret = FALSE;
424 switch (rec->ExceptionCode)
426 case EXCEPTION_ACCESS_VIOLATION:
427 case EXCEPTION_PRIV_INSTRUCTION:
428 case EXCEPTION_STACK_OVERFLOW:
429 case EXCEPTION_GUARD_PAGE:
430 gdbctx->last_sig = SIGSEGV;
431 ret = TRUE;
432 break;
433 case EXCEPTION_DATATYPE_MISALIGNMENT:
434 gdbctx->last_sig = SIGBUS;
435 ret = TRUE;
436 break;
437 case EXCEPTION_SINGLE_STEP:
438 /* fall thru */
439 case EXCEPTION_BREAKPOINT:
440 gdbctx->last_sig = SIGTRAP;
441 ret = TRUE;
442 break;
443 case EXCEPTION_FLT_DENORMAL_OPERAND:
444 case EXCEPTION_FLT_DIVIDE_BY_ZERO:
445 case EXCEPTION_FLT_INEXACT_RESULT:
446 case EXCEPTION_FLT_INVALID_OPERATION:
447 case EXCEPTION_FLT_OVERFLOW:
448 case EXCEPTION_FLT_STACK_CHECK:
449 case EXCEPTION_FLT_UNDERFLOW:
450 gdbctx->last_sig = SIGFPE;
451 ret = TRUE;
452 break;
453 case EXCEPTION_INT_DIVIDE_BY_ZERO:
454 case EXCEPTION_INT_OVERFLOW:
455 gdbctx->last_sig = SIGFPE;
456 ret = TRUE;
457 break;
458 case EXCEPTION_ILLEGAL_INSTRUCTION:
459 gdbctx->last_sig = SIGILL;
460 ret = TRUE;
461 break;
462 case CONTROL_C_EXIT:
463 gdbctx->last_sig = SIGINT;
464 ret = TRUE;
465 break;
466 case STATUS_POSSIBLE_DEADLOCK:
467 gdbctx->last_sig = SIGALRM;
468 ret = TRUE;
469 /* FIXME: we could also add here a O packet with additional information */
470 break;
471 default:
472 if (gdbctx->trace & GDBPXY_TRC_WIN32_EVENT)
473 fprintf(stderr, "Unhandled exception code 0x%08x\n", rec->ExceptionCode);
474 gdbctx->last_sig = SIGABRT;
475 ret = TRUE;
476 break;
478 return ret;
481 static void handle_debug_event(struct gdb_context* gdbctx, DEBUG_EVENT* de)
483 union {
484 char bufferA[256];
485 WCHAR buffer[256];
486 } u;
488 dbg_curr_thread = dbg_get_thread(gdbctx->process, de->dwThreadId);
490 switch (de->dwDebugEventCode)
492 case CREATE_PROCESS_DEBUG_EVENT:
493 gdbctx->process = dbg_add_process(&be_process_gdbproxy_io, de->dwProcessId,
494 de->u.CreateProcessInfo.hProcess);
495 if (!gdbctx->process) break;
496 memory_get_string_indirect(gdbctx->process,
497 de->u.CreateProcessInfo.lpImageName,
498 de->u.CreateProcessInfo.fUnicode,
499 u.buffer, sizeof(u.buffer) / sizeof(WCHAR));
500 dbg_set_process_name(gdbctx->process, u.buffer);
502 if (gdbctx->trace & GDBPXY_TRC_WIN32_EVENT)
503 fprintf(stderr, "%04x:%04x: create process '%s'/%p @%p (%u<%u>)\n",
504 de->dwProcessId, de->dwThreadId,
505 dbg_W2A(u.buffer, -1),
506 de->u.CreateProcessInfo.lpImageName,
507 de->u.CreateProcessInfo.lpStartAddress,
508 de->u.CreateProcessInfo.dwDebugInfoFileOffset,
509 de->u.CreateProcessInfo.nDebugInfoSize);
511 /* de->u.CreateProcessInfo.lpStartAddress; */
512 if (!dbg_init(gdbctx->process->handle, u.buffer, TRUE))
513 fprintf(stderr, "Couldn't initiate DbgHelp\n");
515 if (gdbctx->trace & GDBPXY_TRC_WIN32_EVENT)
516 fprintf(stderr, "%04x:%04x: create thread I @%p\n",
517 de->dwProcessId, de->dwThreadId,
518 de->u.CreateProcessInfo.lpStartAddress);
520 assert(dbg_curr_thread == NULL); /* shouldn't be there */
521 dbg_add_thread(gdbctx->process, de->dwThreadId,
522 de->u.CreateProcessInfo.hThread,
523 de->u.CreateProcessInfo.lpThreadLocalBase);
524 break;
526 case LOAD_DLL_DEBUG_EVENT:
527 assert(dbg_curr_thread);
528 memory_get_string_indirect(gdbctx->process,
529 de->u.LoadDll.lpImageName,
530 de->u.LoadDll.fUnicode,
531 u.buffer, sizeof(u.buffer) / sizeof(WCHAR));
532 if (gdbctx->trace & GDBPXY_TRC_WIN32_EVENT)
533 fprintf(stderr, "%04x:%04x: loads DLL %s @%p (%u<%u>)\n",
534 de->dwProcessId, de->dwThreadId,
535 dbg_W2A(u.buffer, -1),
536 de->u.LoadDll.lpBaseOfDll,
537 de->u.LoadDll.dwDebugInfoFileOffset,
538 de->u.LoadDll.nDebugInfoSize);
539 dbg_load_module(gdbctx->process->handle, de->u.LoadDll.hFile, u.buffer,
540 (DWORD_PTR)de->u.LoadDll.lpBaseOfDll, 0);
541 break;
543 case UNLOAD_DLL_DEBUG_EVENT:
544 if (gdbctx->trace & GDBPXY_TRC_WIN32_EVENT)
545 fprintf(stderr, "%08x:%08x: unload DLL @%p\n",
546 de->dwProcessId, de->dwThreadId, de->u.UnloadDll.lpBaseOfDll);
547 SymUnloadModule(gdbctx->process->handle,
548 (DWORD_PTR)de->u.UnloadDll.lpBaseOfDll);
549 break;
551 case EXCEPTION_DEBUG_EVENT:
552 assert(dbg_curr_thread);
553 if (gdbctx->trace & GDBPXY_TRC_WIN32_EVENT)
554 fprintf(stderr, "%08x:%08x: exception code=0x%08x\n",
555 de->dwProcessId, de->dwThreadId,
556 de->u.Exception.ExceptionRecord.ExceptionCode);
558 if (fetch_context(gdbctx, dbg_curr_thread->handle, &gdbctx->context))
560 gdbctx->in_trap = handle_exception(gdbctx, &de->u.Exception);
562 break;
564 case CREATE_THREAD_DEBUG_EVENT:
565 if (gdbctx->trace & GDBPXY_TRC_WIN32_EVENT)
566 fprintf(stderr, "%08x:%08x: create thread D @%p\n",
567 de->dwProcessId, de->dwThreadId, de->u.CreateThread.lpStartAddress);
569 dbg_add_thread(gdbctx->process,
570 de->dwThreadId,
571 de->u.CreateThread.hThread,
572 de->u.CreateThread.lpThreadLocalBase);
573 break;
575 case EXIT_THREAD_DEBUG_EVENT:
576 if (gdbctx->trace & GDBPXY_TRC_WIN32_EVENT)
577 fprintf(stderr, "%08x:%08x: exit thread (%u)\n",
578 de->dwProcessId, de->dwThreadId, de->u.ExitThread.dwExitCode);
580 assert(dbg_curr_thread);
581 if (dbg_curr_thread == gdbctx->exec_thread) gdbctx->exec_thread = NULL;
582 if (dbg_curr_thread == gdbctx->other_thread) gdbctx->other_thread = NULL;
583 dbg_del_thread(dbg_curr_thread);
584 break;
586 case EXIT_PROCESS_DEBUG_EVENT:
587 if (gdbctx->trace & GDBPXY_TRC_WIN32_EVENT)
588 fprintf(stderr, "%08x:%08x: exit process (%u)\n",
589 de->dwProcessId, de->dwThreadId, de->u.ExitProcess.dwExitCode);
591 dbg_del_process(gdbctx->process);
592 gdbctx->process = NULL;
593 /* now signal gdb that we're done */
594 gdbctx->last_sig = SIGTERM;
595 gdbctx->in_trap = TRUE;
596 break;
598 case OUTPUT_DEBUG_STRING_EVENT:
599 assert(dbg_curr_thread);
600 memory_get_string(gdbctx->process,
601 de->u.DebugString.lpDebugStringData, TRUE,
602 de->u.DebugString.fUnicode, u.bufferA, sizeof(u.bufferA));
603 if (gdbctx->trace & GDBPXY_TRC_WIN32_EVENT)
604 fprintf(stderr, "%08x:%08x: output debug string (%s)\n",
605 de->dwProcessId, de->dwThreadId, u.bufferA);
606 break;
608 case RIP_EVENT:
609 if (gdbctx->trace & GDBPXY_TRC_WIN32_EVENT)
610 fprintf(stderr, "%08x:%08x: rip error=%u type=%u\n",
611 de->dwProcessId, de->dwThreadId, de->u.RipInfo.dwError,
612 de->u.RipInfo.dwType);
613 break;
615 default:
616 if (gdbctx->trace & GDBPXY_TRC_WIN32_EVENT)
617 fprintf(stderr, "%08x:%08x: unknown event (%u)\n",
618 de->dwProcessId, de->dwThreadId, de->dwDebugEventCode);
622 static void resume_debuggee(struct gdb_context* gdbctx, DWORD cont)
624 if (dbg_curr_thread)
626 if (!SetThreadContext(dbg_curr_thread->handle, &gdbctx->context))
627 if (gdbctx->trace & GDBPXY_TRC_WIN32_ERROR)
628 fprintf(stderr, "Cannot set context on thread %04x\n", dbg_curr_thread->tid);
629 if (!ContinueDebugEvent(gdbctx->process->pid, dbg_curr_thread->tid, cont))
630 if (gdbctx->trace & GDBPXY_TRC_WIN32_ERROR)
631 fprintf(stderr, "Cannot continue on %04x (%x)\n",
632 dbg_curr_thread->tid, cont);
634 else if (gdbctx->trace & GDBPXY_TRC_WIN32_ERROR)
635 fprintf(stderr, "Cannot find last thread\n");
639 static void resume_debuggee_thread(struct gdb_context* gdbctx, DWORD cont, unsigned int threadid)
642 if (dbg_curr_thread)
644 if(dbg_curr_thread->tid == threadid){
645 /* Windows debug and GDB don't seem to work well here, windows only likes ContinueDebugEvent being used on the reporter of the event */
646 if (!SetThreadContext(dbg_curr_thread->handle, &gdbctx->context))
647 if (gdbctx->trace & GDBPXY_TRC_WIN32_ERROR)
648 fprintf(stderr, "Cannot set context on thread %04x\n", dbg_curr_thread->tid);
649 if (!ContinueDebugEvent(gdbctx->process->pid, dbg_curr_thread->tid, cont))
650 if (gdbctx->trace & GDBPXY_TRC_WIN32_ERROR)
651 fprintf(stderr, "Cannot continue on %04x (%x)\n",
652 dbg_curr_thread->tid, cont);
655 else if (gdbctx->trace & GDBPXY_TRC_WIN32_ERROR)
656 fprintf(stderr, "Cannot find last thread\n");
659 static BOOL check_for_interrupt(struct gdb_context* gdbctx)
661 struct pollfd pollfd;
662 int ret;
663 char pkt;
665 pollfd.fd = gdbctx->sock;
666 pollfd.events = POLLIN;
667 pollfd.revents = 0;
669 if ((ret = poll(&pollfd, 1, 0)) == 1) {
670 ret = read(gdbctx->sock, &pkt, 1);
671 if (ret != 1) {
672 if (gdbctx->trace & GDBPXY_TRC_WIN32_ERROR) {
673 fprintf(stderr, "read failed\n");
675 return FALSE;
677 if (pkt != '\003') {
678 if (gdbctx->trace & GDBPXY_TRC_COMMAND_ERROR) {
679 fprintf(stderr, "Unexpected break packet (%c/0x%X)\n", pkt, pkt);
681 return FALSE;
683 return TRUE;
684 } else if (ret == -1) {
685 fprintf(stderr, "poll failed\n");
687 return FALSE;
690 static void wait_for_debuggee(struct gdb_context* gdbctx)
692 DEBUG_EVENT de;
694 gdbctx->in_trap = FALSE;
695 for (;;)
697 if (!WaitForDebugEvent(&de, 10))
699 if (GetLastError() == ERROR_SEM_TIMEOUT)
701 if (check_for_interrupt(gdbctx)) {
702 if (!DebugBreakProcess(gdbctx->process->handle)) {
703 if (gdbctx->trace & GDBPXY_TRC_WIN32_ERROR) {
704 fprintf(stderr, "Failed to break into debugee\n");
706 break;
708 WaitForDebugEvent(&de, INFINITE);
709 } else {
710 continue;
712 } else {
713 break;
716 handle_debug_event(gdbctx, &de);
717 assert(!gdbctx->process ||
718 gdbctx->process->pid == 0 ||
719 de.dwProcessId == gdbctx->process->pid);
720 assert(!dbg_curr_thread || de.dwThreadId == dbg_curr_thread->tid);
721 if (gdbctx->in_trap) break;
722 ContinueDebugEvent(de.dwProcessId, de.dwThreadId, DBG_CONTINUE);
726 static void detach_debuggee(struct gdb_context* gdbctx, BOOL kill)
728 be_cpu->single_step(&gdbctx->context, FALSE);
729 resume_debuggee(gdbctx, DBG_CONTINUE);
730 if (!kill)
731 DebugActiveProcessStop(gdbctx->process->pid);
732 dbg_del_process(gdbctx->process);
733 gdbctx->process = NULL;
736 static void get_process_info(struct gdb_context* gdbctx, char* buffer, size_t len)
738 DWORD status;
740 if (!GetExitCodeProcess(gdbctx->process->handle, &status))
742 strcpy(buffer, "Unknown process");
743 return;
745 if (status == STILL_ACTIVE)
747 strcpy(buffer, "Running");
749 else
750 snprintf(buffer, len, "Terminated (%u)", status);
752 switch (GetPriorityClass(gdbctx->process->handle))
754 case 0: break;
755 #ifdef ABOVE_NORMAL_PRIORITY_CLASS
756 case ABOVE_NORMAL_PRIORITY_CLASS: strcat(buffer, ", above normal priority"); break;
757 #endif
758 #ifdef BELOW_NORMAL_PRIORITY_CLASS
759 case BELOW_NORMAL_PRIORITY_CLASS: strcat(buffer, ", below normal priotity"); break;
760 #endif
761 case HIGH_PRIORITY_CLASS: strcat(buffer, ", high priority"); break;
762 case IDLE_PRIORITY_CLASS: strcat(buffer, ", idle priority"); break;
763 case NORMAL_PRIORITY_CLASS: strcat(buffer, ", normal priority"); break;
764 case REALTIME_PRIORITY_CLASS: strcat(buffer, ", realtime priority"); break;
766 strcat(buffer, "\n");
769 static void get_thread_info(struct gdb_context* gdbctx, unsigned tid,
770 char* buffer, size_t len)
772 struct dbg_thread* thd;
773 DWORD status;
774 int prio;
776 /* FIXME: use the size of buffer */
777 thd = dbg_get_thread(gdbctx->process, tid);
778 if (thd == NULL)
780 strcpy(buffer, "No information");
781 return;
783 if (GetExitCodeThread(thd->handle, &status))
785 if (status == STILL_ACTIVE)
787 /* FIXME: this is a bit brutal... some nicer way shall be found */
788 switch (status = SuspendThread(thd->handle))
790 case -1: break;
791 case 0: strcpy(buffer, "Running"); break;
792 default: snprintf(buffer, len, "Suspended (%u)", status - 1);
794 ResumeThread(thd->handle);
796 else
797 snprintf(buffer, len, "Terminated (exit code = %u)", status);
799 else
801 strcpy(buffer, "Unknown threadID");
803 switch (prio = GetThreadPriority(thd->handle))
805 case THREAD_PRIORITY_ERROR_RETURN: break;
806 case THREAD_PRIORITY_ABOVE_NORMAL: strcat(buffer, ", priority +1 above normal"); break;
807 case THREAD_PRIORITY_BELOW_NORMAL: strcat(buffer, ", priority -1 below normal"); break;
808 case THREAD_PRIORITY_HIGHEST: strcat(buffer, ", priority +2 above normal"); break;
809 case THREAD_PRIORITY_LOWEST: strcat(buffer, ", priority -2 below normal"); break;
810 case THREAD_PRIORITY_IDLE: strcat(buffer, ", priority idle"); break;
811 case THREAD_PRIORITY_NORMAL: strcat(buffer, ", priority normal"); break;
812 case THREAD_PRIORITY_TIME_CRITICAL: strcat(buffer, ", priority time-critical"); break;
813 default: snprintf(buffer + strlen(buffer), len - strlen(buffer), ", priority = %d", prio);
815 assert(strlen(buffer) < len);
818 /* =============================================== *
819 * P A C K E T U T I L S *
820 * =============================================== *
823 enum packet_return {packet_error = 0x00, packet_ok = 0x01, packet_done = 0x02,
824 packet_last_f = 0x80};
826 static char* packet_realloc(char* buf, int size)
828 if (!buf)
829 return HeapAlloc(GetProcessHeap(), 0, size);
830 return HeapReAlloc(GetProcessHeap(), 0, buf, size);
834 static void packet_reply_grow(struct gdb_context* gdbctx, size_t size)
836 if (gdbctx->out_buf_alloc < gdbctx->out_len + size)
838 gdbctx->out_buf_alloc = ((gdbctx->out_len + size) / 32 + 1) * 32;
839 gdbctx->out_buf = packet_realloc(gdbctx->out_buf, gdbctx->out_buf_alloc);
843 static void packet_reply_hex_to(struct gdb_context* gdbctx, const void* src, int len)
845 packet_reply_grow(gdbctx, len * 2);
846 hex_to(&gdbctx->out_buf[gdbctx->out_len], src, len);
847 gdbctx->out_len += len * 2;
850 static inline void packet_reply_hex_to_str(struct gdb_context* gdbctx, const char* src)
852 packet_reply_hex_to(gdbctx, src, strlen(src));
855 static void packet_reply_val(struct gdb_context* gdbctx, unsigned long val, int len)
857 int i, shift;
859 shift = (len - 1) * 8;
860 packet_reply_grow(gdbctx, len * 2);
861 for (i = 0; i < len; i++, shift -= 8)
863 gdbctx->out_buf[gdbctx->out_len++] = hex_to0((val >> (shift + 4)) & 0x0F);
864 gdbctx->out_buf[gdbctx->out_len++] = hex_to0((val >> shift ) & 0x0F);
868 static inline void packet_reply_add(struct gdb_context* gdbctx, const char* str, int len)
870 packet_reply_grow(gdbctx, len);
871 memcpy(&gdbctx->out_buf[gdbctx->out_len], str, len);
872 gdbctx->out_len += len;
875 static inline void packet_reply_cat(struct gdb_context* gdbctx, const char* str)
877 packet_reply_add(gdbctx, str, strlen(str));
880 static inline void packet_reply_catc(struct gdb_context* gdbctx, char ch)
882 packet_reply_add(gdbctx, &ch, 1);
885 static void packet_reply_open(struct gdb_context* gdbctx)
887 assert(gdbctx->out_curr_packet == -1);
888 packet_reply_catc(gdbctx, '$');
889 gdbctx->out_curr_packet = gdbctx->out_len;
892 static void packet_reply_close(struct gdb_context* gdbctx)
894 unsigned char cksum;
895 int plen;
897 plen = gdbctx->out_len - gdbctx->out_curr_packet;
898 packet_reply_catc(gdbctx, '#');
899 cksum = checksum(&gdbctx->out_buf[gdbctx->out_curr_packet], plen);
900 packet_reply_hex_to(gdbctx, &cksum, 1);
901 if (gdbctx->trace & GDBPXY_TRC_PACKET)
902 fprintf(stderr, "Reply : %*.*s\n",
903 plen, plen, &gdbctx->out_buf[gdbctx->out_curr_packet]);
904 gdbctx->out_curr_packet = -1;
907 static enum packet_return packet_reply(struct gdb_context* gdbctx, const char* packet, int len)
909 packet_reply_open(gdbctx);
911 if (len == -1) len = strlen(packet);
912 assert(memchr(packet, '$', len) == NULL && memchr(packet, '#', len) == NULL);
914 packet_reply_add(gdbctx, packet, len);
916 packet_reply_close(gdbctx);
918 return packet_done;
921 static enum packet_return packet_reply_error(struct gdb_context* gdbctx, int error)
923 packet_reply_open(gdbctx);
925 packet_reply_add(gdbctx, "E", 1);
926 packet_reply_val(gdbctx, error, 1);
928 packet_reply_close(gdbctx);
930 return packet_done;
933 /* =============================================== *
934 * P A C K E T H A N D L E R S *
935 * =============================================== *
938 static enum packet_return packet_reply_status(struct gdb_context* gdbctx)
940 enum packet_return ret = packet_done;
942 packet_reply_open(gdbctx);
944 if (gdbctx->process != NULL)
946 unsigned char sig;
947 unsigned i;
949 packet_reply_catc(gdbctx, 'T');
950 sig = gdbctx->last_sig;
951 packet_reply_val(gdbctx, sig, 1);
952 packet_reply_add(gdbctx, "thread:", 7);
953 packet_reply_val(gdbctx, dbg_curr_thread->tid, 4);
954 packet_reply_catc(gdbctx, ';');
956 for (i = 0; i < cpu_num_regs; i++)
958 /* FIXME: this call will also grow the buffer...
959 * unneeded, but not harmful
961 packet_reply_val(gdbctx, i, 1);
962 packet_reply_catc(gdbctx, ':');
963 packet_reply_hex_to(gdbctx, cpu_register(&gdbctx->context, i), 4);
964 packet_reply_catc(gdbctx, ';');
967 else
969 /* Try to put an exit code
970 * Cannot use GetExitCodeProcess, wouldn't fit in a 8 bit value, so
971 * just indicate the end of process and exit */
972 packet_reply_add(gdbctx, "W00", 3);
973 /*if (!gdbctx->extended)*/ ret |= packet_last_f;
976 packet_reply_close(gdbctx);
978 return ret;
981 #if 0
982 static enum packet_return packet_extended(struct gdb_context* gdbctx)
984 gdbctx->extended = 1;
985 return packet_ok;
987 #endif
989 static enum packet_return packet_last_signal(struct gdb_context* gdbctx)
991 assert(gdbctx->in_packet_len == 0);
992 return packet_reply_status(gdbctx);
995 static enum packet_return packet_continue(struct gdb_context* gdbctx)
997 /* FIXME: add support for address in packet */
998 assert(gdbctx->in_packet_len == 0);
999 if (dbg_curr_thread != gdbctx->exec_thread && gdbctx->exec_thread)
1000 if (gdbctx->trace & GDBPXY_TRC_COMMAND_FIXME)
1001 fprintf(stderr, "NIY: cont on %04x, while last thread is %04x\n",
1002 gdbctx->exec_thread->tid, dbg_curr_thread->tid);
1003 resume_debuggee(gdbctx, DBG_CONTINUE);
1004 wait_for_debuggee(gdbctx);
1005 return packet_reply_status(gdbctx);
1008 static enum packet_return packet_verbose(struct gdb_context* gdbctx)
1010 int i;
1011 int defaultAction = -1; /* magic non action */
1012 unsigned char sig;
1013 int actions =0;
1014 int actionIndex[20]; /* allow for up to 20 actions */
1015 int threadIndex[20];
1016 int threadCount = 0;
1017 unsigned int threadIDs[100]; /* TODO: Should make this dynamic */
1018 unsigned int threadID = 0;
1019 struct dbg_thread* thd;
1021 /* basic check */
1022 assert(gdbctx->in_packet_len >= 4);
1024 /* OK we have vCont followed by..
1025 * ? for query
1026 * c for packet_continue
1027 * Csig for packet_continue_signal
1028 * s for step
1029 * Ssig for step signal
1030 * and then an optional thread ID at the end..
1031 * *******************************************/
1033 fprintf(stderr, "trying to process a verbose packet\n");
1034 /* now check that we've got Cont */
1035 assert(strncmp(gdbctx->in_packet, "Cont", 4) == 0);
1037 /* Query */
1038 if (gdbctx->in_packet[4] == '?')
1041 Reply:
1042 `vCont[;action]...'
1043 The vCont packet is supported. Each action is a supported command in the vCont packet.
1045 The vCont packet is not supported. (this didn't seem to be obeyed!)
1047 packet_reply_open(gdbctx);
1048 packet_reply_add(gdbctx, "vCont", 5);
1049 /* add all the supported actions to the reply (all of them for now) */
1050 packet_reply_add(gdbctx, ";c", 2);
1051 packet_reply_add(gdbctx, ";C", 2);
1052 packet_reply_add(gdbctx, ";s", 2);
1053 packet_reply_add(gdbctx, ";S", 2);
1054 packet_reply_close(gdbctx);
1055 return packet_done;
1058 /* This may not be the 'fastest' code in the world. but it should be nice and easy to debug.
1059 (as it's run when people are debugging break points I'm sure they won't notice the extra 100 cycles anyway)
1060 now if only gdb talked XML.... */
1061 #if 0 /* handy for debugging */
1062 fprintf(stderr, "no, but can we find a default packet %.*s %d\n", gdbctx->in_packet_len, gdbctx->in_packet, gdbctx->in_packet_len);
1063 #endif
1065 /* go through the packet and identify where all the actions start at */
1066 for (i = 4; i < gdbctx->in_packet_len - 1; i++)
1068 if (gdbctx->in_packet[i] == ';')
1070 threadIndex[actions] = 0;
1071 actionIndex[actions++] = i;
1073 else if (gdbctx->in_packet[i] == ':')
1075 threadIndex[actions - 1] = i;
1079 /* now look up the default action */
1080 for (i = 0 ; i < actions; i++)
1082 if (threadIndex[i] == 0)
1084 if (defaultAction != -1)
1086 fprintf(stderr,"Too many default actions specified\n");
1087 return packet_error;
1089 defaultAction = i;
1093 /* Now, I have this default action thing that needs to be applied to all non counted threads */
1095 /* go through all the threads and stick their ids in the to be done list. */
1096 for (thd = gdbctx->process->threads; thd; thd = thd->next)
1098 threadIDs[threadCount++] = thd->tid;
1099 /* check to see if we have more threads than I counted on, and tell the user what to do
1100 * (they're running winedbg, so I'm sure they can fix the problem from the error message!) */
1101 if (threadCount == 100)
1103 fprintf(stderr, "Wow, that's a lot of threads, change threadIDs in wine/programms/winedgb/gdbproxy.c to be higher\n");
1104 break;
1108 /* Ok, now we have... actionIndex full of actions and we know what threads there are, so all
1109 * that remains is to apply the actions to the threads and the default action to any threads
1110 * left */
1111 if (dbg_curr_thread != gdbctx->exec_thread && gdbctx->exec_thread)
1112 if (gdbctx->trace & GDBPXY_TRC_COMMAND_FIXME)
1113 fprintf(stderr, "NIY: cont on %04x, while last thread is %04x\n",
1114 gdbctx->exec_thread->tid, dbg_curr_thread->tid);
1116 /* deal with the threaded stuff first */
1117 for (i = 0; i < actions ; i++)
1119 if (threadIndex[i] != 0)
1121 int j, idLength = 0;
1122 if (i < actions - 1)
1124 idLength = (actionIndex[i+1] - threadIndex[i]) - 1;
1126 else
1128 idLength = (gdbctx->in_packet_len - threadIndex[i]) - 1;
1131 threadID = hex_to_int(gdbctx->in_packet + threadIndex[i] + 1 , idLength);
1132 /* process the action */
1133 switch (gdbctx->in_packet[actionIndex[i] + 1])
1135 case 's': /* step */
1136 be_cpu->single_step(&gdbctx->context, TRUE);
1137 /* fall through*/
1138 case 'c': /* continue */
1139 resume_debuggee_thread(gdbctx, DBG_CONTINUE, threadID);
1140 break;
1141 case 'S': /* step Sig, */
1142 be_cpu->single_step(&gdbctx->context, TRUE);
1143 /* fall through */
1144 case 'C': /* continue sig */
1145 hex_from(&sig, gdbctx->in_packet + actionIndex[i] + 2, 1);
1146 /* cannot change signals on the fly */
1147 if (gdbctx->trace & GDBPXY_TRC_COMMAND)
1148 fprintf(stderr, "sigs: %u %u\n", sig, gdbctx->last_sig);
1149 if (sig != gdbctx->last_sig)
1150 return packet_error;
1151 resume_debuggee_thread(gdbctx, DBG_EXCEPTION_NOT_HANDLED, threadID);
1152 break;
1154 for (j = 0 ; j < threadCount; j++)
1156 if (threadIDs[j] == threadID)
1158 threadIDs[j] = 0;
1159 break;
1163 } /* for i=0 ; i< actions */
1165 /* now we have manage the default action */
1166 if (defaultAction >= 0)
1168 for (i = 0 ; i< threadCount; i++)
1170 /* check to see if we've already done something to the thread*/
1171 if (threadIDs[i] != 0)
1173 /* if not apply the default action*/
1174 threadID = threadIDs[i];
1175 /* process the action (yes this is almost identical to the one above!) */
1176 switch (gdbctx->in_packet[actionIndex[defaultAction] + 1])
1178 case 's': /* step */
1179 be_cpu->single_step(&gdbctx->context, TRUE);
1180 /* fall through */
1181 case 'c': /* continue */
1182 resume_debuggee_thread(gdbctx, DBG_CONTINUE, threadID);
1183 break;
1184 case 'S':
1185 be_cpu->single_step(&gdbctx->context, TRUE);
1186 /* fall through */
1187 case 'C': /* continue sig */
1188 hex_from(&sig, gdbctx->in_packet + actionIndex[defaultAction] + 2, 1);
1189 /* cannot change signals on the fly */
1190 if (gdbctx->trace & GDBPXY_TRC_COMMAND)
1191 fprintf(stderr, "sigs: %u %u\n", sig, gdbctx->last_sig);
1192 if (sig != gdbctx->last_sig)
1193 return packet_error;
1194 resume_debuggee_thread(gdbctx, DBG_EXCEPTION_NOT_HANDLED, threadID);
1195 break;
1199 } /* if(defaultAction >=0) */
1201 wait_for_debuggee(gdbctx);
1202 be_cpu->single_step(&gdbctx->context, FALSE);
1203 return packet_reply_status(gdbctx);
1206 static enum packet_return packet_continue_signal(struct gdb_context* gdbctx)
1208 unsigned char sig;
1210 /* FIXME: add support for address in packet */
1211 assert(gdbctx->in_packet_len == 2);
1212 if (dbg_curr_thread != gdbctx->exec_thread && gdbctx->exec_thread)
1213 if (gdbctx->trace & GDBPXY_TRC_COMMAND_FIXME)
1214 fprintf(stderr, "NIY: cont/sig on %04x, while last thread is %04x\n",
1215 gdbctx->exec_thread->tid, dbg_curr_thread->tid);
1216 hex_from(&sig, gdbctx->in_packet, 1);
1217 /* cannot change signals on the fly */
1218 if (gdbctx->trace & GDBPXY_TRC_COMMAND)
1219 fprintf(stderr, "sigs: %u %u\n", sig, gdbctx->last_sig);
1220 if (sig != gdbctx->last_sig)
1221 return packet_error;
1222 resume_debuggee(gdbctx, DBG_EXCEPTION_NOT_HANDLED);
1223 wait_for_debuggee(gdbctx);
1224 return packet_reply_status(gdbctx);
1227 static enum packet_return packet_detach(struct gdb_context* gdbctx)
1229 detach_debuggee(gdbctx, FALSE);
1230 return packet_ok | packet_last_f;
1233 static enum packet_return packet_read_registers(struct gdb_context* gdbctx)
1235 int i;
1236 CONTEXT ctx;
1237 CONTEXT* pctx = &gdbctx->context;
1239 assert(gdbctx->in_trap);
1241 if (dbg_curr_thread != gdbctx->other_thread && gdbctx->other_thread)
1243 if (!fetch_context(gdbctx, gdbctx->other_thread->handle, pctx = &ctx))
1244 return packet_error;
1247 packet_reply_open(gdbctx);
1248 for (i = 0; i < cpu_num_regs; i++)
1250 packet_reply_hex_to(gdbctx, cpu_register(pctx, i), 4);
1252 packet_reply_close(gdbctx);
1253 return packet_done;
1256 static enum packet_return packet_write_registers(struct gdb_context* gdbctx)
1258 unsigned i;
1259 CONTEXT ctx;
1260 CONTEXT* pctx = &gdbctx->context;
1262 assert(gdbctx->in_trap);
1263 if (dbg_curr_thread != gdbctx->other_thread && gdbctx->other_thread)
1265 if (!fetch_context(gdbctx, gdbctx->other_thread->handle, pctx = &ctx))
1266 return packet_error;
1268 if (gdbctx->in_packet_len < cpu_num_regs * 2) return packet_error;
1270 for (i = 0; i < cpu_num_regs; i++)
1271 hex_from(cpu_register(pctx, i), &gdbctx->in_packet[8 * i], 4);
1272 if (pctx != &gdbctx->context && !SetThreadContext(gdbctx->other_thread->handle, pctx))
1274 if (gdbctx->trace & GDBPXY_TRC_WIN32_ERROR)
1275 fprintf(stderr, "Cannot set context on thread %04x\n", gdbctx->other_thread->tid);
1276 return packet_error;
1278 return packet_ok;
1281 static enum packet_return packet_kill(struct gdb_context* gdbctx)
1283 detach_debuggee(gdbctx, TRUE);
1284 #if 0
1285 if (!gdbctx->extended)
1286 /* dunno whether GDB cares or not */
1287 #endif
1288 wait(NULL);
1289 exit(0);
1290 /* assume we can't really answer something here */
1291 /* return packet_done; */
1294 static enum packet_return packet_thread(struct gdb_context* gdbctx)
1296 char* end;
1297 unsigned thread;
1299 switch (gdbctx->in_packet[0])
1301 case 'c':
1302 case 'g':
1303 if (gdbctx->in_packet[1] == '-')
1304 thread = -strtol(gdbctx->in_packet + 2, &end, 16);
1305 else
1306 thread = strtol(gdbctx->in_packet + 1, &end, 16);
1307 if (end == NULL || end > gdbctx->in_packet + gdbctx->in_packet_len)
1309 if (gdbctx->trace & GDBPXY_TRC_COMMAND_ERROR)
1310 fprintf(stderr, "Cannot get threadid %*.*s\n",
1311 gdbctx->in_packet_len - 1, gdbctx->in_packet_len - 1,
1312 gdbctx->in_packet + 1);
1313 return packet_error;
1315 if (gdbctx->in_packet[0] == 'c')
1316 gdbctx->exec_thread = dbg_get_thread(gdbctx->process, thread);
1317 else
1318 gdbctx->other_thread = dbg_get_thread(gdbctx->process, thread);
1319 return packet_ok;
1320 default:
1321 if (gdbctx->trace & GDBPXY_TRC_COMMAND_ERROR)
1322 fprintf(stderr, "Unknown thread sub-command %c\n", gdbctx->in_packet[0]);
1323 return packet_error;
1327 static enum packet_return packet_read_memory(struct gdb_context* gdbctx)
1329 char *addr;
1330 unsigned int len, blk_len, nread;
1331 char buffer[32];
1332 SIZE_T r = 0;
1334 assert(gdbctx->in_trap);
1335 /* FIXME:check in_packet_len for reading %p,%x */
1336 if (sscanf(gdbctx->in_packet, "%p,%x", &addr, &len) != 2) return packet_error;
1337 if (len <= 0) return packet_error;
1338 if (gdbctx->trace & GDBPXY_TRC_COMMAND)
1339 fprintf(stderr, "Read mem at %p for %u bytes\n", addr, len);
1340 for (nread = 0; nread < len; nread += r, addr += r)
1342 blk_len = min(sizeof(buffer), len - nread);
1343 if (!gdbctx->process->process_io->read(gdbctx->process->handle, addr, buffer, blk_len, &r) ||
1344 r == 0)
1346 /* fail at first address, return error */
1347 if (nread == 0) return packet_reply_error(gdbctx, EFAULT);
1348 /* something has already been read, return partial information */
1349 break;
1351 if (nread == 0) packet_reply_open(gdbctx);
1352 packet_reply_hex_to(gdbctx, buffer, r);
1354 packet_reply_close(gdbctx);
1355 return packet_done;
1358 static enum packet_return packet_write_memory(struct gdb_context* gdbctx)
1360 char* addr;
1361 unsigned int len, blk_len;
1362 char* ptr;
1363 char buffer[32];
1364 SIZE_T w;
1366 assert(gdbctx->in_trap);
1367 ptr = memchr(gdbctx->in_packet, ':', gdbctx->in_packet_len);
1368 if (ptr == NULL)
1370 if (gdbctx->trace & GDBPXY_TRC_COMMAND_ERROR)
1371 fprintf(stderr, "Cannot find ':' in %*.*s\n",
1372 gdbctx->in_packet_len, gdbctx->in_packet_len, gdbctx->in_packet);
1373 return packet_error;
1375 *ptr++ = '\0';
1377 if (sscanf(gdbctx->in_packet, "%p,%x", &addr, &len) != 2)
1379 if (gdbctx->trace & GDBPXY_TRC_COMMAND_ERROR)
1380 fprintf(stderr, "Cannot scan addr,len in %s\n", gdbctx->in_packet);
1381 return packet_error;
1383 if (ptr - gdbctx->in_packet + len * 2 != gdbctx->in_packet_len)
1385 if (gdbctx->trace & GDBPXY_TRC_COMMAND_ERROR)
1386 fprintf(stderr, "Wrong sizes %u <> %u\n",
1387 ptr - gdbctx->in_packet + len * 2, gdbctx->in_packet_len);
1388 return packet_error;
1390 if (gdbctx->trace & GDBPXY_TRC_COMMAND)
1391 fprintf(stderr, "Write %u bytes at %p\n", len, addr);
1392 while (len > 0)
1394 blk_len = min(sizeof(buffer), len);
1395 hex_from(buffer, ptr, blk_len);
1396 if (!gdbctx->process->process_io->write(gdbctx->process->handle, addr, buffer, blk_len, &w) ||
1397 w != blk_len)
1398 break;
1399 addr += blk_len;
1400 len -= blk_len;
1401 ptr += blk_len;
1403 return packet_ok; /* FIXME: error while writing ? */
1406 static enum packet_return packet_read_register(struct gdb_context* gdbctx)
1408 unsigned reg;
1409 CONTEXT ctx;
1410 CONTEXT* pctx = &gdbctx->context;
1412 assert(gdbctx->in_trap);
1413 reg = hex_to_int(gdbctx->in_packet, gdbctx->in_packet_len);
1414 if (reg >= cpu_num_regs)
1416 if (gdbctx->trace & GDBPXY_TRC_COMMAND_ERROR)
1417 fprintf(stderr, "Register out of bounds %x\n", reg);
1418 return packet_error;
1420 if (dbg_curr_thread != gdbctx->other_thread && gdbctx->other_thread)
1422 if (!fetch_context(gdbctx, gdbctx->other_thread->handle, pctx = &ctx))
1423 return packet_error;
1425 if (gdbctx->trace & GDBPXY_TRC_COMMAND)
1426 fprintf(stderr, "Read register %x => %lx\n", reg, *cpu_register(pctx, reg));
1427 packet_reply_open(gdbctx);
1428 packet_reply_hex_to(gdbctx, cpu_register(pctx, reg), 4);
1429 packet_reply_close(gdbctx);
1430 return packet_done;
1433 static enum packet_return packet_write_register(struct gdb_context* gdbctx)
1435 unsigned reg;
1436 char* ptr;
1437 char* end;
1438 CONTEXT ctx;
1439 CONTEXT* pctx = &gdbctx->context;
1441 assert(gdbctx->in_trap);
1443 ptr = memchr(gdbctx->in_packet, '=', gdbctx->in_packet_len);
1444 *ptr++ = '\0';
1445 reg = strtoul(gdbctx->in_packet, &end, 16);
1446 if (end == NULL || reg > cpu_num_regs)
1448 if (gdbctx->trace & GDBPXY_TRC_COMMAND_ERROR)
1449 fprintf(stderr, "Invalid register index %s\n", gdbctx->in_packet);
1450 /* FIXME: if just the reg is above cpu_num_regs, don't tell gdb
1451 * it wouldn't matter too much, and it fakes our support for all regs
1453 return (end == NULL) ? packet_error : packet_ok;
1455 if (ptr + 8 - gdbctx->in_packet != gdbctx->in_packet_len)
1457 if (gdbctx->trace & GDBPXY_TRC_COMMAND_ERROR)
1458 fprintf(stderr, "Wrong sizes %u <> %u\n",
1459 ptr + 8 - gdbctx->in_packet, gdbctx->in_packet_len);
1460 return packet_error;
1462 if (gdbctx->trace & GDBPXY_TRC_COMMAND)
1463 fprintf(stderr, "Writing reg %u <= %*.*s\n",
1464 reg, gdbctx->in_packet_len - (ptr - gdbctx->in_packet),
1465 gdbctx->in_packet_len - (ptr - gdbctx->in_packet), ptr);
1467 if (dbg_curr_thread != gdbctx->other_thread && gdbctx->other_thread)
1469 if (!fetch_context(gdbctx, gdbctx->other_thread->handle, pctx = &ctx))
1470 return packet_error;
1473 hex_from(cpu_register(pctx, reg), ptr, 4);
1474 if (pctx != &gdbctx->context && !SetThreadContext(gdbctx->other_thread->handle, pctx))
1476 if (gdbctx->trace & GDBPXY_TRC_WIN32_ERROR)
1477 fprintf(stderr, "Cannot set context for thread %04x\n", gdbctx->other_thread->tid);
1478 return packet_error;
1481 return packet_ok;
1484 static void packet_query_monitor_wnd_helper(struct gdb_context* gdbctx, HWND hWnd, int indent)
1486 char buffer[128];
1487 char clsName[128];
1488 char wndName[128];
1489 HWND child;
1491 do {
1492 if (!GetClassName(hWnd, clsName, sizeof(clsName)))
1493 strcpy(clsName, "-- Unknown --");
1494 if (!GetWindowText(hWnd, wndName, sizeof(wndName)))
1495 strcpy(wndName, "-- Empty --");
1497 packet_reply_open(gdbctx);
1498 packet_reply_catc(gdbctx, 'O');
1499 snprintf(buffer, sizeof(buffer),
1500 "%*s%04lx%*s%-17.17s %08x %08x %.14s\n",
1501 indent, "", (ULONG_PTR)hWnd, 13 - indent, "",
1502 clsName, GetWindowLong(hWnd, GWL_STYLE),
1503 GetWindowLongPtr(hWnd, GWLP_WNDPROC), wndName);
1504 packet_reply_hex_to_str(gdbctx, buffer);
1505 packet_reply_close(gdbctx);
1507 if ((child = GetWindow(hWnd, GW_CHILD)) != 0)
1508 packet_query_monitor_wnd_helper(gdbctx, child, indent + 1);
1509 } while ((hWnd = GetWindow(hWnd, GW_HWNDNEXT)) != 0);
1512 static void packet_query_monitor_wnd(struct gdb_context* gdbctx, int len, const char* str)
1514 char buffer[128];
1516 /* we do the output in several 'O' packets, with the last one being just OK for
1517 * marking the end of the output */
1518 packet_reply_open(gdbctx);
1519 packet_reply_catc(gdbctx, 'O');
1520 snprintf(buffer, sizeof(buffer),
1521 "%-16.16s %-17.17s %-8.8s %s\n",
1522 "hwnd", "Class Name", " Style", " WndProc Text");
1523 packet_reply_hex_to_str(gdbctx, buffer);
1524 packet_reply_close(gdbctx);
1526 /* FIXME: could also add a pmt to this command in str... */
1527 packet_query_monitor_wnd_helper(gdbctx, GetDesktopWindow(), 0);
1528 packet_reply(gdbctx, "OK", 2);
1531 static void packet_query_monitor_process(struct gdb_context* gdbctx, int len, const char* str)
1533 HANDLE snap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
1534 char buffer[128];
1535 char deco;
1536 PROCESSENTRY32 entry;
1537 BOOL ok;
1539 if (snap == INVALID_HANDLE_VALUE)
1540 return;
1542 entry.dwSize = sizeof(entry);
1543 ok = Process32First(snap, &entry);
1545 /* we do the output in several 'O' packets, with the last one being just OK for
1546 * marking the end of the output */
1548 packet_reply_open(gdbctx);
1549 packet_reply_catc(gdbctx, 'O');
1550 snprintf(buffer, sizeof(buffer),
1551 " %-8.8s %-8.8s %-8.8s %s\n",
1552 "pid", "threads", "parent", "executable");
1553 packet_reply_hex_to_str(gdbctx, buffer);
1554 packet_reply_close(gdbctx);
1556 while (ok)
1558 deco = ' ';
1559 if (entry.th32ProcessID == gdbctx->process->pid) deco = '>';
1560 packet_reply_open(gdbctx);
1561 packet_reply_catc(gdbctx, 'O');
1562 snprintf(buffer, sizeof(buffer),
1563 "%c%08x %-8d %08x '%s'\n",
1564 deco, entry.th32ProcessID, entry.cntThreads,
1565 entry.th32ParentProcessID, entry.szExeFile);
1566 packet_reply_hex_to_str(gdbctx, buffer);
1567 packet_reply_close(gdbctx);
1568 ok = Process32Next(snap, &entry);
1570 CloseHandle(snap);
1571 packet_reply(gdbctx, "OK", 2);
1574 static void packet_query_monitor_mem(struct gdb_context* gdbctx, int len, const char* str)
1576 MEMORY_BASIC_INFORMATION mbi;
1577 char* addr = 0;
1578 const char* state;
1579 const char* type;
1580 char prot[3+1];
1581 char buffer[128];
1583 /* we do the output in several 'O' packets, with the last one being just OK for
1584 * marking the end of the output */
1585 packet_reply_open(gdbctx);
1586 packet_reply_catc(gdbctx, 'O');
1587 packet_reply_hex_to_str(gdbctx, "Address Size State Type RWX\n");
1588 packet_reply_close(gdbctx);
1590 while (VirtualQueryEx(gdbctx->process->handle, addr, &mbi, sizeof(mbi)) >= sizeof(mbi))
1592 switch (mbi.State)
1594 case MEM_COMMIT: state = "commit "; break;
1595 case MEM_FREE: state = "free "; break;
1596 case MEM_RESERVE: state = "reserve"; break;
1597 default: state = "??? "; break;
1599 if (mbi.State != MEM_FREE)
1601 switch (mbi.Type)
1603 case MEM_IMAGE: type = "image "; break;
1604 case MEM_MAPPED: type = "mapped "; break;
1605 case MEM_PRIVATE: type = "private"; break;
1606 case 0: type = " "; break;
1607 default: type = "??? "; break;
1609 memset(prot, ' ' , sizeof(prot)-1);
1610 prot[sizeof(prot)-1] = '\0';
1611 if (mbi.AllocationProtect & (PAGE_READONLY|PAGE_READWRITE|PAGE_EXECUTE_READ|PAGE_EXECUTE_READWRITE))
1612 prot[0] = 'R';
1613 if (mbi.AllocationProtect & (PAGE_READWRITE|PAGE_EXECUTE_READWRITE))
1614 prot[1] = 'W';
1615 if (mbi.AllocationProtect & (PAGE_WRITECOPY|PAGE_EXECUTE_WRITECOPY))
1616 prot[1] = 'C';
1617 if (mbi.AllocationProtect & (PAGE_EXECUTE|PAGE_EXECUTE_READ|PAGE_EXECUTE_READWRITE))
1618 prot[2] = 'X';
1620 else
1622 type = "";
1623 prot[0] = '\0';
1625 packet_reply_open(gdbctx);
1626 snprintf(buffer, sizeof(buffer), "%08lx %08lx %s %s %s\n",
1627 (DWORD_PTR)addr, mbi.RegionSize, state, type, prot);
1628 packet_reply_catc(gdbctx, 'O');
1629 packet_reply_hex_to_str(gdbctx, buffer);
1630 packet_reply_close(gdbctx);
1632 if (addr + mbi.RegionSize < addr) /* wrap around ? */
1633 break;
1634 addr += mbi.RegionSize;
1636 packet_reply(gdbctx, "OK", 2);
1639 static void packet_query_monitor_trace(struct gdb_context* gdbctx,
1640 int len, const char* str)
1642 char buffer[128];
1644 if (len == 0)
1646 snprintf(buffer, sizeof(buffer), "trace=%x\n", gdbctx->trace);
1648 else if (len >= 2 && str[0] == '=')
1650 unsigned val = atoi(&str[1]);
1651 snprintf(buffer, sizeof(buffer), "trace: %x => %x\n", gdbctx->trace, val);
1652 gdbctx->trace = val;
1654 else
1656 /* FIXME: ugly but can use error packet here */
1657 packet_reply_cat(gdbctx, "E00");
1658 return;
1660 packet_reply_open(gdbctx);
1661 packet_reply_hex_to_str(gdbctx, buffer);
1662 packet_reply_close(gdbctx);
1665 struct query_detail
1667 int with_arg;
1668 const char* name;
1669 size_t len;
1670 void (*handler)(struct gdb_context*, int, const char*);
1671 } query_details[] =
1673 {0, "wnd", 3, packet_query_monitor_wnd},
1674 {0, "window", 6, packet_query_monitor_wnd},
1675 {0, "proc", 4, packet_query_monitor_process},
1676 {0, "process", 7, packet_query_monitor_process},
1677 {0, "mem", 3, packet_query_monitor_mem},
1678 {1, "trace", 5, packet_query_monitor_trace},
1679 {0, NULL, 0, NULL},
1682 static enum packet_return packet_query_remote_command(struct gdb_context* gdbctx,
1683 const char* hxcmd, size_t len)
1685 char buffer[128];
1686 struct query_detail* qd;
1688 assert((len & 1) == 0 && len < 2 * sizeof(buffer));
1689 len /= 2;
1690 hex_from(buffer, hxcmd, len);
1692 for (qd = &query_details[0]; qd->name != NULL; qd++)
1694 if (len < qd->len || strncmp(buffer, qd->name, qd->len) != 0) continue;
1695 if (!qd->with_arg && len != qd->len) continue;
1697 (qd->handler)(gdbctx, len - qd->len, buffer + qd->len);
1698 return packet_done;
1700 return packet_reply_error(gdbctx, EINVAL);
1703 static enum packet_return packet_query(struct gdb_context* gdbctx)
1705 switch (gdbctx->in_packet[0])
1707 case 'f':
1708 if (strncmp(gdbctx->in_packet + 1, "ThreadInfo", gdbctx->in_packet_len - 1) == 0)
1710 struct dbg_thread* thd;
1712 packet_reply_open(gdbctx);
1713 packet_reply_add(gdbctx, "m", 1);
1714 for (thd = gdbctx->process->threads; thd; thd = thd->next)
1716 packet_reply_val(gdbctx, thd->tid, 4);
1717 if (thd->next != NULL)
1718 packet_reply_add(gdbctx, ",", 1);
1720 packet_reply_close(gdbctx);
1721 return packet_done;
1723 else if (strncmp(gdbctx->in_packet + 1, "ProcessInfo", gdbctx->in_packet_len - 1) == 0)
1725 char result[128];
1727 packet_reply_open(gdbctx);
1728 packet_reply_catc(gdbctx, 'O');
1729 get_process_info(gdbctx, result, sizeof(result));
1730 packet_reply_hex_to_str(gdbctx, result);
1731 packet_reply_close(gdbctx);
1732 return packet_done;
1734 break;
1735 case 's':
1736 if (strncmp(gdbctx->in_packet + 1, "ThreadInfo", gdbctx->in_packet_len - 1) == 0)
1738 packet_reply(gdbctx, "l", 1);
1739 return packet_done;
1741 else if (strncmp(gdbctx->in_packet + 1, "ProcessInfo", gdbctx->in_packet_len - 1) == 0)
1743 packet_reply(gdbctx, "l", 1);
1744 return packet_done;
1746 break;
1747 case 'C':
1748 if (gdbctx->in_packet_len == 1)
1750 struct dbg_thread* thd;
1751 /* FIXME: doc says 16 bit val ??? */
1752 /* grab first created thread, aka last in list */
1753 assert(gdbctx->process && gdbctx->process->threads);
1754 for (thd = gdbctx->process->threads; thd->next; thd = thd->next);
1755 packet_reply_open(gdbctx);
1756 packet_reply_add(gdbctx, "QC", 2);
1757 packet_reply_val(gdbctx, thd->tid, 4);
1758 packet_reply_close(gdbctx);
1759 return packet_done;
1761 break;
1762 case 'O':
1763 if (strncmp(gdbctx->in_packet, "Offsets", gdbctx->in_packet_len) == 0)
1765 char buf[64];
1767 if (gdbctx->wine_segs[0] == 0 && gdbctx->wine_segs[1] == 0 &&
1768 gdbctx->wine_segs[2] == 0)
1769 return packet_error;
1770 snprintf(buf, sizeof(buf),
1771 "Text=%08lx;Data=%08lx;Bss=%08lx",
1772 gdbctx->wine_segs[0], gdbctx->wine_segs[1],
1773 gdbctx->wine_segs[2]);
1774 return packet_reply(gdbctx, buf, -1);
1776 break;
1777 case 'R':
1778 if (gdbctx->in_packet_len > 5 && strncmp(gdbctx->in_packet, "Rcmd,", 5) == 0)
1780 return packet_query_remote_command(gdbctx, gdbctx->in_packet + 5,
1781 gdbctx->in_packet_len - 5);
1783 break;
1784 case 'S':
1785 if (strncmp(gdbctx->in_packet, "Symbol::", gdbctx->in_packet_len) == 0)
1786 return packet_ok;
1787 if (strncmp(gdbctx->in_packet, "Supported", gdbctx->in_packet_len) == 0)
1789 packet_reply_open(gdbctx);
1790 packet_reply_close(gdbctx);
1791 return packet_done;
1793 break;
1794 case 'T':
1795 if (gdbctx->in_packet_len > 15 &&
1796 strncmp(gdbctx->in_packet, "ThreadExtraInfo", 15) == 0 &&
1797 gdbctx->in_packet[15] == ',')
1799 unsigned tid;
1800 char* end;
1801 char result[128];
1803 tid = strtol(gdbctx->in_packet + 16, &end, 16);
1804 if (end == NULL) break;
1805 get_thread_info(gdbctx, tid, result, sizeof(result));
1806 packet_reply_open(gdbctx);
1807 packet_reply_hex_to_str(gdbctx, result);
1808 packet_reply_close(gdbctx);
1809 return packet_done;
1811 break;
1813 if (gdbctx->trace & GDBPXY_TRC_COMMAND_ERROR)
1814 fprintf(stderr, "Unknown or malformed query %*.*s\n",
1815 gdbctx->in_packet_len, gdbctx->in_packet_len, gdbctx->in_packet);
1816 return packet_error;
1819 static enum packet_return packet_step(struct gdb_context* gdbctx)
1821 /* FIXME: add support for address in packet */
1822 assert(gdbctx->in_packet_len == 0);
1823 if (dbg_curr_thread != gdbctx->exec_thread && gdbctx->exec_thread)
1824 if (gdbctx->trace & GDBPXY_TRC_COMMAND_FIXME)
1825 fprintf(stderr, "NIY: step on %04x, while last thread is %04x\n",
1826 gdbctx->exec_thread->tid, dbg_curr_thread->tid);
1827 be_cpu->single_step(&gdbctx->context, TRUE);
1828 resume_debuggee(gdbctx, DBG_CONTINUE);
1829 wait_for_debuggee(gdbctx);
1830 be_cpu->single_step(&gdbctx->context, FALSE);
1831 return packet_reply_status(gdbctx);
1834 #if 0
1835 static enum packet_return packet_step_signal(struct gdb_context* gdbctx)
1837 unsigned char sig;
1839 /* FIXME: add support for address in packet */
1840 assert(gdbctx->in_packet_len == 2);
1841 if (dbg_curr_thread->tid != gdbctx->exec_thread && gdbctx->exec_thread)
1842 if (gdbctx->trace & GDBPXY_TRC_COMMAND_ERROR)
1843 fprintf(stderr, "NIY: step/sig on %u, while last thread is %u\n",
1844 gdbctx->exec_thread, DEBUG_CurrThread->tid);
1845 hex_from(&sig, gdbctx->in_packet, 1);
1846 /* cannot change signals on the fly */
1847 if (gdbctx->trace & GDBPXY_TRC_COMMAND)
1848 fprintf(stderr, "sigs: %u %u\n", sig, gdbctx->last_sig);
1849 if (sig != gdbctx->last_sig)
1850 return packet_error;
1851 resume_debuggee(gdbctx, DBG_EXCEPTION_NOT_HANDLED);
1852 wait_for_debuggee(gdbctx);
1853 return packet_reply_status(gdbctx);
1855 #endif
1857 static enum packet_return packet_thread_alive(struct gdb_context* gdbctx)
1859 char* end;
1860 unsigned tid;
1862 tid = strtol(gdbctx->in_packet, &end, 16);
1863 if (tid == -1 || tid == 0)
1864 return packet_reply_error(gdbctx, EINVAL);
1865 if (dbg_get_thread(gdbctx->process, tid) != NULL)
1866 return packet_ok;
1867 return packet_reply_error(gdbctx, ESRCH);
1870 static enum packet_return packet_remove_breakpoint(struct gdb_context* gdbctx)
1872 void* addr;
1873 unsigned len;
1874 struct gdb_ctx_Xpoint* xpt;
1875 enum be_xpoint_type t;
1877 /* FIXME: check packet_len */
1878 if (gdbctx->in_packet[0] < '0' || gdbctx->in_packet[0] > '4' ||
1879 gdbctx->in_packet[1] != ',' ||
1880 sscanf(gdbctx->in_packet + 2, "%p,%x", &addr, &len) != 2)
1881 return packet_error;
1882 if (gdbctx->trace & GDBPXY_TRC_COMMAND)
1883 fprintf(stderr, "Remove bp %p[%u] typ=%c\n",
1884 addr, len, gdbctx->in_packet[0]);
1885 switch (gdbctx->in_packet[0])
1887 case '0': t = be_xpoint_break; len = 0; break;
1888 case '1': t = be_xpoint_watch_exec; break;
1889 case '2': t = be_xpoint_watch_read; break;
1890 case '3': t = be_xpoint_watch_write; break;
1891 default: return packet_error;
1893 for (xpt = &gdbctx->Xpoints[NUM_XPOINT - 1]; xpt >= gdbctx->Xpoints; xpt--)
1895 if (xpt->addr == addr && xpt->type == t)
1897 if (be_cpu->remove_Xpoint(gdbctx->process->handle,
1898 gdbctx->process->process_io, &gdbctx->context,
1899 t, xpt->addr, xpt->val, len))
1901 xpt->type = -1;
1902 return packet_ok;
1904 break;
1907 return packet_error;
1910 static enum packet_return packet_set_breakpoint(struct gdb_context* gdbctx)
1912 void* addr;
1913 unsigned len;
1914 struct gdb_ctx_Xpoint* xpt;
1915 enum be_xpoint_type t;
1917 /* FIXME: check packet_len */
1918 if (gdbctx->in_packet[0] < '0' || gdbctx->in_packet[0] > '4' ||
1919 gdbctx->in_packet[1] != ',' ||
1920 sscanf(gdbctx->in_packet + 2, "%p,%x", &addr, &len) != 2)
1921 return packet_error;
1922 if (gdbctx->trace & GDBPXY_TRC_COMMAND)
1923 fprintf(stderr, "Set bp %p[%u] typ=%c\n",
1924 addr, len, gdbctx->in_packet[0]);
1925 switch (gdbctx->in_packet[0])
1927 case '0': t = be_xpoint_break; len = 0; break;
1928 case '1': t = be_xpoint_watch_exec; break;
1929 case '2': t = be_xpoint_watch_read; break;
1930 case '3': t = be_xpoint_watch_write; break;
1931 default: return packet_error;
1933 /* because of packet command handling, this should be made idempotent */
1934 for (xpt = &gdbctx->Xpoints[NUM_XPOINT - 1]; xpt >= gdbctx->Xpoints; xpt--)
1936 if (xpt->addr == addr && xpt->type == t)
1937 return packet_ok; /* nothing to do */
1939 /* really set the Xpoint */
1940 for (xpt = &gdbctx->Xpoints[NUM_XPOINT - 1]; xpt >= gdbctx->Xpoints; xpt--)
1942 if (xpt->type == -1)
1944 if (be_cpu->insert_Xpoint(gdbctx->process->handle,
1945 gdbctx->process->process_io, &gdbctx->context,
1946 t, addr, &xpt->val, len))
1948 xpt->addr = addr;
1949 xpt->type = t;
1950 return packet_ok;
1952 fprintf(stderr, "cannot set xpoint\n");
1953 break;
1956 /* no more entries... eech */
1957 fprintf(stderr, "Running out of spots for {break|watch}points\n");
1958 return packet_error;
1961 /* =============================================== *
1962 * P A C K E T I N F R A S T R U C T U R E *
1963 * =============================================== *
1966 struct packet_entry
1968 char key;
1969 enum packet_return (*handler)(struct gdb_context* gdbctx);
1972 static struct packet_entry packet_entries[] =
1974 /*{'!', packet_extended}, */
1975 {'?', packet_last_signal},
1976 {'c', packet_continue},
1977 {'C', packet_continue_signal},
1978 {'D', packet_detach},
1979 {'g', packet_read_registers},
1980 {'G', packet_write_registers},
1981 {'k', packet_kill},
1982 {'H', packet_thread},
1983 {'m', packet_read_memory},
1984 {'M', packet_write_memory},
1985 {'p', packet_read_register},
1986 {'P', packet_write_register},
1987 {'q', packet_query},
1988 /* {'Q', packet_set}, */
1989 /* {'R', packet,restart}, only in extended mode ! */
1990 {'s', packet_step},
1991 /*{'S', packet_step_signal}, hard(er) to implement */
1992 {'T', packet_thread_alive},
1993 {'v', packet_verbose},
1994 {'z', packet_remove_breakpoint},
1995 {'Z', packet_set_breakpoint},
1998 static BOOL extract_packets(struct gdb_context* gdbctx)
2000 char* end;
2001 int plen;
2002 unsigned char in_cksum, loc_cksum;
2003 char* ptr;
2004 enum packet_return ret = packet_error;
2005 int num_packet = 0;
2007 while ((ret & packet_last_f) == 0)
2009 if (gdbctx->in_len && (gdbctx->trace & GDBPXY_TRC_LOWLEVEL))
2010 fprintf(stderr, "In-buf: %*.*s\n",
2011 gdbctx->in_len, gdbctx->in_len, gdbctx->in_buf);
2012 ptr = memchr(gdbctx->in_buf, '$', gdbctx->in_len);
2013 if (ptr == NULL) return FALSE;
2014 if (ptr != gdbctx->in_buf)
2016 int glen = ptr - gdbctx->in_buf; /* garbage len */
2017 if (gdbctx->trace & GDBPXY_TRC_LOWLEVEL)
2018 fprintf(stderr, "Removing garbage: %*.*s\n",
2019 glen, glen, gdbctx->in_buf);
2020 gdbctx->in_len -= glen;
2021 memmove(gdbctx->in_buf, ptr, gdbctx->in_len);
2023 end = memchr(gdbctx->in_buf + 1, '#', gdbctx->in_len);
2024 if (end == NULL) return FALSE;
2025 /* no checksum yet */
2026 if (end + 3 > gdbctx->in_buf + gdbctx->in_len) return FALSE;
2027 plen = end - gdbctx->in_buf - 1;
2028 hex_from(&in_cksum, end + 1, 1);
2029 loc_cksum = checksum(gdbctx->in_buf + 1, plen);
2030 if (loc_cksum == in_cksum)
2032 if (num_packet == 0) {
2033 int i;
2035 ret = packet_error;
2037 write(gdbctx->sock, "+", 1);
2038 assert(plen);
2040 /* FIXME: should use bsearch if packet_entries was sorted */
2041 for (i = 0; i < sizeof(packet_entries)/sizeof(packet_entries[0]); i++)
2043 if (packet_entries[i].key == gdbctx->in_buf[1]) break;
2045 if (i == sizeof(packet_entries)/sizeof(packet_entries[0]))
2047 if (gdbctx->trace & GDBPXY_TRC_COMMAND_ERROR)
2048 fprintf(stderr, "Unknown packet request %*.*s\n",
2049 plen, plen, &gdbctx->in_buf[1]);
2051 else
2053 gdbctx->in_packet = gdbctx->in_buf + 2;
2054 gdbctx->in_packet_len = plen - 1;
2055 if (gdbctx->trace & GDBPXY_TRC_PACKET)
2056 fprintf(stderr, "Packet: %c%*.*s\n",
2057 gdbctx->in_buf[1],
2058 gdbctx->in_packet_len, gdbctx->in_packet_len,
2059 gdbctx->in_packet);
2060 ret = (packet_entries[i].handler)(gdbctx);
2062 switch (ret & ~packet_last_f)
2064 case packet_error: packet_reply(gdbctx, "", 0); break;
2065 case packet_ok: packet_reply(gdbctx, "OK", 2); break;
2066 case packet_done: break;
2068 if (gdbctx->trace & GDBPXY_TRC_LOWLEVEL)
2069 fprintf(stderr, "Reply-full: %*.*s\n",
2070 gdbctx->out_len, gdbctx->out_len, gdbctx->out_buf);
2071 i = write(gdbctx->sock, gdbctx->out_buf, gdbctx->out_len);
2072 assert(i == gdbctx->out_len);
2073 /* if this fails, we'll have to use POLLOUT...
2075 gdbctx->out_len = 0;
2076 num_packet++;
2078 else
2080 /* FIXME: if we have in our input buffer more than one packet,
2081 * it's very likely that we took too long to answer to a given packet
2082 * and gdb is sending us again the same packet
2083 * We simply drop the second packet. This will lower the risk of error,
2084 * but there's still some race conditions here
2085 * A better fix (yet not perfect) would be to have two threads:
2086 * - one managing the packets for gdb
2087 * - the second one managing the commands...
2088 * This would allow us also the reply with the '+' character (Ack of
2089 * the command) way sooner than what we do now
2091 if (gdbctx->trace & GDBPXY_TRC_LOWLEVEL)
2092 fprintf(stderr, "Dropping packet, I was too slow to respond\n");
2095 else
2097 write(gdbctx->sock, "+", 1);
2098 if (gdbctx->trace & GDBPXY_TRC_LOWLEVEL)
2099 fprintf(stderr, "Dropping packet, invalid checksum %d <> %d\n", in_cksum, loc_cksum);
2101 gdbctx->in_len -= plen + 4;
2102 memmove(gdbctx->in_buf, end + 3, gdbctx->in_len);
2104 return TRUE;
2107 static int fetch_data(struct gdb_context* gdbctx)
2109 int len, in_len = gdbctx->in_len;
2111 assert(gdbctx->in_len <= gdbctx->in_buf_alloc);
2112 for (;;)
2114 #define STEP 128
2115 if (gdbctx->in_len + STEP > gdbctx->in_buf_alloc)
2116 gdbctx->in_buf = packet_realloc(gdbctx->in_buf, gdbctx->in_buf_alloc += STEP);
2117 #undef STEP
2118 if (gdbctx->trace & GDBPXY_TRC_LOWLEVEL)
2119 fprintf(stderr, "%d %d %*.*s\n",
2120 gdbctx->in_len, gdbctx->in_buf_alloc,
2121 gdbctx->in_len, gdbctx->in_len, gdbctx->in_buf);
2122 len = read(gdbctx->sock, gdbctx->in_buf + gdbctx->in_len, gdbctx->in_buf_alloc - gdbctx->in_len);
2123 if (len <= 0) break;
2124 gdbctx->in_len += len;
2125 assert(gdbctx->in_len <= gdbctx->in_buf_alloc);
2126 if (len < gdbctx->in_buf_alloc - gdbctx->in_len) break;
2128 if (gdbctx->trace & GDBPXY_TRC_LOWLEVEL)
2129 fprintf(stderr, "=> %d\n", gdbctx->in_len - in_len);
2130 return gdbctx->in_len - in_len;
2133 #define FLAG_NO_START 1
2134 #define FLAG_WITH_XTERM 2
2136 static BOOL gdb_exec(const char* wine_path, unsigned port, unsigned flags)
2138 char buf[MAX_PATH];
2139 int fd;
2140 const char* gdb_path;
2141 FILE* f;
2143 if (!(gdb_path = getenv("WINE_GDB"))) gdb_path = "gdb";
2144 strcpy(buf,"/tmp/winegdb.XXXXXX");
2145 fd = mkstemps(buf, 0);
2146 if (fd == -1) return FALSE;
2147 if ((f = fdopen(fd, "w+")) == NULL) return FALSE;
2148 fprintf(f, "file %s\n", wine_path);
2149 fprintf(f, "target remote localhost:%d\n", ntohs(port));
2150 fprintf(f, "monitor trace=%d\n", GDBPXY_TRC_COMMAND_FIXME);
2151 fprintf(f, "set prompt Wine-gdb>\\ \n");
2152 /* gdb 5.1 seems to require it, won't hurt anyway */
2153 fprintf(f, "sharedlibrary\n");
2154 /* This is needed (but not a decent & final fix)
2155 * Without this, gdb would skip our inter-DLL relay code (because
2156 * we don't have any line number information for the relay code)
2157 * With this, we will stop on first instruction of the stub, and
2158 * reusing step, will get us through the relay stub at the actual
2159 * function we're looking at.
2161 fprintf(f, "set step-mode on\n");
2162 /* tell gdb to delete this file when done handling it... */
2163 fprintf(f, "shell rm -f \"%s\"\n", buf);
2164 fclose(f);
2165 if (flags & FLAG_WITH_XTERM)
2166 execlp("xterm", "xterm", "-e", gdb_path, "-x", buf, NULL);
2167 else
2168 execlp(gdb_path, gdb_path, "-x", buf, NULL);
2169 assert(0); /* never reached */
2170 return TRUE;
2173 static BOOL gdb_startup(struct gdb_context* gdbctx, DEBUG_EVENT* de, unsigned flags)
2175 int sock;
2176 struct sockaddr_in s_addrs;
2177 unsigned int s_len = sizeof(s_addrs);
2178 struct pollfd pollfd;
2179 IMAGEHLP_MODULE imh_mod;
2181 /* step 1: create socket for gdb connection request */
2182 if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1)
2184 if (gdbctx->trace & GDBPXY_TRC_LOWLEVEL)
2185 fprintf(stderr, "Can't create socket");
2186 return FALSE;
2189 if (listen(sock, 1) == -1 ||
2190 getsockname(sock, (struct sockaddr*)&s_addrs, &s_len) == -1)
2191 return FALSE;
2193 /* step 2: do the process internal creation */
2194 handle_debug_event(gdbctx, de);
2196 /* step3: get the wine loader name */
2197 if (!dbg_get_debuggee_info(gdbctx->process->handle, &imh_mod)) return FALSE;
2199 /* step 4: fire up gdb (if requested) */
2200 if (flags & FLAG_NO_START)
2201 fprintf(stderr, "target remote localhost:%d\n", ntohs(s_addrs.sin_port));
2202 else
2203 switch (fork())
2205 case -1: /* error in parent... */
2206 fprintf(stderr, "Cannot create gdb\n");
2207 return FALSE;
2208 default: /* in parent... success */
2209 break;
2210 case 0: /* in child... and alive */
2211 gdb_exec(imh_mod.LoadedImageName, s_addrs.sin_port, flags);
2212 /* if we're here, exec failed, so report failure */
2213 return FALSE;
2216 /* step 5: wait for gdb to connect actually */
2217 pollfd.fd = sock;
2218 pollfd.events = POLLIN;
2219 pollfd.revents = 0;
2221 switch (poll(&pollfd, 1, -1))
2223 case 1:
2224 if (pollfd.revents & POLLIN)
2226 int dummy = 1;
2227 gdbctx->sock = accept(sock, (struct sockaddr*)&s_addrs, &s_len);
2228 if (gdbctx->sock == -1)
2229 break;
2230 if (gdbctx->trace & GDBPXY_TRC_LOWLEVEL)
2231 fprintf(stderr, "Connected on %d\n", gdbctx->sock);
2232 /* don't keep our small packets too long: send them ASAP back to GDB
2233 * without this, GDB really crawls
2235 setsockopt(gdbctx->sock, IPPROTO_TCP, TCP_NODELAY, (char*)&dummy, sizeof(dummy));
2237 break;
2238 case 0:
2239 if (gdbctx->trace & GDBPXY_TRC_LOWLEVEL)
2240 fprintf(stderr, "Poll for cnx failed (timeout)\n");
2241 return FALSE;
2242 case -1:
2243 if (gdbctx->trace & GDBPXY_TRC_LOWLEVEL)
2244 fprintf(stderr, "Poll for cnx failed (error)\n");
2245 return FALSE;
2246 default:
2247 assert(0);
2250 close(sock);
2251 return TRUE;
2254 static BOOL gdb_init_context(struct gdb_context* gdbctx, unsigned flags)
2256 DEBUG_EVENT de;
2257 int i;
2259 gdbctx->sock = -1;
2260 gdbctx->in_buf = NULL;
2261 gdbctx->in_buf_alloc = 0;
2262 gdbctx->in_len = 0;
2263 gdbctx->out_buf = NULL;
2264 gdbctx->out_buf_alloc = 0;
2265 gdbctx->out_len = 0;
2266 gdbctx->out_curr_packet = -1;
2268 gdbctx->exec_thread = gdbctx->other_thread = NULL;
2269 gdbctx->last_sig = 0;
2270 gdbctx->in_trap = FALSE;
2271 gdbctx->trace = /*GDBPXY_TRC_PACKET | GDBPXY_TRC_COMMAND |*/ GDBPXY_TRC_COMMAND_ERROR | GDBPXY_TRC_COMMAND_FIXME | GDBPXY_TRC_WIN32_EVENT;
2272 gdbctx->process = NULL;
2273 for (i = 0; i < NUM_XPOINT; i++)
2274 gdbctx->Xpoints[i].type = -1;
2276 /* wait for first trap */
2277 while (WaitForDebugEvent(&de, INFINITE))
2279 if (de.dwDebugEventCode == CREATE_PROCESS_DEBUG_EVENT)
2281 /* this should be the first event we get,
2282 * and the only one of this type */
2283 assert(gdbctx->process == NULL && de.dwProcessId == dbg_curr_pid);
2284 /* gdbctx->dwProcessId = pid; */
2285 if (!gdb_startup(gdbctx, &de, flags)) return FALSE;
2286 assert(!gdbctx->in_trap);
2288 else
2290 handle_debug_event(gdbctx, &de);
2291 if (gdbctx->in_trap) break;
2293 ContinueDebugEvent(de.dwProcessId, de.dwThreadId, DBG_CONTINUE);
2295 return TRUE;
2298 static int gdb_remote(unsigned flags)
2300 struct pollfd pollfd;
2301 struct gdb_context gdbctx;
2302 BOOL doLoop;
2304 for (doLoop = gdb_init_context(&gdbctx, flags); doLoop;)
2306 pollfd.fd = gdbctx.sock;
2307 pollfd.events = POLLIN;
2308 pollfd.revents = 0;
2310 switch (poll(&pollfd, 1, -1))
2312 case 1:
2313 /* got something */
2314 if (pollfd.revents & (POLLHUP | POLLERR))
2316 if (gdbctx.trace & GDBPXY_TRC_LOWLEVEL)
2317 fprintf(stderr, "Gdb hung up\n");
2318 /* kill also debuggee process - questionnable - */
2319 detach_debuggee(&gdbctx, TRUE);
2320 doLoop = FALSE;
2321 break;
2323 if ((pollfd.revents & POLLIN) && fetch_data(&gdbctx) > 0)
2325 if (extract_packets(&gdbctx)) doLoop = FALSE;
2327 break;
2328 case 0:
2329 /* timeout, should never happen (infinite timeout) */
2330 break;
2331 case -1:
2332 if (gdbctx.trace & GDBPXY_TRC_LOWLEVEL)
2333 fprintf(stderr, "Poll failed\n");
2334 doLoop = FALSE;
2335 break;
2338 wait(NULL);
2339 return 0;
2341 #endif
2343 int gdb_main(int argc, char* argv[])
2345 #ifdef HAVE_POLL
2346 unsigned gdb_flags = 0;
2348 argc--; argv++;
2349 while (argc > 0 && argv[0][0] == '-')
2351 if (strcmp(argv[0], "--no-start") == 0)
2353 gdb_flags |= FLAG_NO_START;
2354 argc--; argv++;
2355 continue;
2357 if (strcmp(argv[0], "--with-xterm") == 0)
2359 gdb_flags |= FLAG_WITH_XTERM;
2360 argc--; argv++;
2361 continue;
2363 return -1;
2365 if (dbg_active_attach(argc, argv) == start_ok ||
2366 dbg_active_launch(argc, argv) == start_ok)
2367 return gdb_remote(gdb_flags);
2368 #else
2369 fprintf(stderr, "GdbProxy mode not supported on this platform\n");
2370 #endif
2371 return -1;