1 /* Low level interface to Windows debugging, for gdbserver.
2 Copyright (C) 2006, 2007 Free Software Foundation, Inc.
4 Contributed by Leo Zayas. Based on "win32-nat.c" from GDB.
6 This file is part of GDB.
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 This program 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
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 Boston, MA 02110-1301, USA. */
25 #include "gdb/signals.h"
30 #include <sys/param.h>
35 #include <sys/cygwin.h>
40 #define OUTMSG(X) do { printf X; fflush (stdout); } while (0)
42 #define OUTMSG2(X) do { printf X; fflush (stdout); } while (0)
47 int using_threads
= 1;
50 static HANDLE current_process_handle
= NULL
;
51 static DWORD current_process_id
= 0;
52 static enum target_signal last_sig
= TARGET_SIGNAL_0
;
54 /* The current debug event from WaitForDebugEvent. */
55 static DEBUG_EVENT current_event
;
57 static int debug_registers_changed
= 0;
58 static int debug_registers_used
= 0;
59 static unsigned dr
[8];
61 typedef BOOL
winapi_DebugActiveProcessStop (DWORD dwProcessId
);
62 typedef BOOL
winapi_DebugSetProcessKillOnExit (BOOL KillOnExit
);
64 #define FLAG_TRACE_BIT 0x100
65 #define CONTEXT_DEBUGGER (CONTEXT_FULL | CONTEXT_FLOATING_POINT)
66 #define CONTEXT_DEBUGGER_DR CONTEXT_DEBUGGER | CONTEXT_DEBUG_REGISTERS \
67 | CONTEXT_EXTENDED_REGISTERS
69 /* Thread information structure used to track extra information about
71 typedef struct thread_info_struct
78 static DWORD main_thread_id
= 0;
80 /* Get the thread ID from the current selected inferior (the current
83 current_inferior_tid (void)
85 thread_info
*th
= inferior_target_data (current_inferior
);
89 /* Find a thread record given a thread id. If GET_CONTEXT is set then
90 also retrieve the context for this thread. */
92 thread_rec (DWORD id
, int get_context
)
94 struct thread_info
*thread
;
97 thread
= (struct thread_info
*) find_inferior_id (&all_threads
, id
);
101 th
= inferior_target_data (thread
);
102 if (!th
->suspend_count
&& get_context
)
104 if (get_context
> 0 && id
!= current_event
.dwThreadId
)
105 th
->suspend_count
= SuspendThread (th
->h
) + 1;
106 else if (get_context
< 0)
107 th
->suspend_count
= -1;
109 th
->context
.ContextFlags
= CONTEXT_DEBUGGER_DR
;
111 GetThreadContext (th
->h
, &th
->context
);
113 if (id
== current_event
.dwThreadId
)
115 /* Copy dr values from that thread. */
116 dr
[0] = th
->context
.Dr0
;
117 dr
[1] = th
->context
.Dr1
;
118 dr
[2] = th
->context
.Dr2
;
119 dr
[3] = th
->context
.Dr3
;
120 dr
[6] = th
->context
.Dr6
;
121 dr
[7] = th
->context
.Dr7
;
128 /* Add a thread to the thread list. */
130 child_add_thread (DWORD tid
, HANDLE h
)
134 if ((th
= thread_rec (tid
, FALSE
)))
137 th
= (thread_info
*) malloc (sizeof (*th
));
138 memset (th
, 0, sizeof (*th
));
142 add_thread (tid
, th
, (unsigned int) tid
);
143 set_inferior_regcache_data ((struct thread_info
*)
144 find_inferior_id (&all_threads
, tid
),
145 new_register_cache ());
147 /* Set the debug registers for the new thread if they are used. */
148 if (debug_registers_used
)
150 /* Only change the value of the debug registers. */
151 th
->context
.ContextFlags
= CONTEXT_DEBUGGER_DR
;
153 GetThreadContext (th
->h
, &th
->context
);
155 th
->context
.Dr0
= dr
[0];
156 th
->context
.Dr1
= dr
[1];
157 th
->context
.Dr2
= dr
[2];
158 th
->context
.Dr3
= dr
[3];
159 /* th->context.Dr6 = dr[6];
160 FIXME: should we set dr6 also ?? */
161 th
->context
.Dr7
= dr
[7];
162 SetThreadContext (th
->h
, &th
->context
);
163 th
->context
.ContextFlags
= 0;
169 /* Delete a thread from the list of threads. */
171 delete_thread_info (struct inferior_list_entry
*thread
)
173 thread_info
*th
= inferior_target_data ((struct thread_info
*) thread
);
175 remove_thread ((struct thread_info
*) thread
);
180 /* Delete a thread from the list of threads. */
182 child_delete_thread (DWORD id
)
184 struct inferior_list_entry
*thread
;
186 /* If the last thread is exiting, just return. */
187 if (all_threads
.head
== all_threads
.tail
)
190 thread
= find_inferior_id (&all_threads
, id
);
194 delete_thread_info (thread
);
197 /* Transfer memory from/to the debugged process. */
199 child_xfer_memory (CORE_ADDR memaddr
, char *our
, int len
,
200 int write
, struct target_ops
*target
)
203 long addr
= (long) memaddr
;
207 WriteProcessMemory (current_process_handle
, (LPVOID
) addr
,
208 (LPCVOID
) our
, len
, &done
);
209 FlushInstructionCache (current_process_handle
, (LPCVOID
) addr
, len
);
213 ReadProcessMemory (current_process_handle
, (LPCVOID
) addr
, (LPVOID
) our
,
219 /* Generally, what has the program done? */
222 /* The program has exited. The exit status is in value.integer. */
223 TARGET_WAITKIND_EXITED
,
225 /* The program has stopped with a signal. Which signal is in
227 TARGET_WAITKIND_STOPPED
,
229 /* The program is letting us know that it dynamically loaded something
230 (e.g. it called load(2) on AIX). */
231 TARGET_WAITKIND_LOADED
,
233 /* The program has exec'ed a new executable file. The new file's
234 pathname is pointed to by value.execd_pathname. */
236 TARGET_WAITKIND_EXECD
,
238 /* Nothing happened, but we stopped anyway. This perhaps should be handled
239 within target_wait, but I'm not sure target_wait should be resuming the
241 TARGET_WAITKIND_SPURIOUS
,
244 struct target_waitstatus
246 enum target_waitkind kind
;
248 /* Forked child pid, execd pathname, exit status or signal number. */
252 enum target_signal sig
;
254 char *execd_pathname
;
261 #define FCS_REGNUM 27
262 #define FOP_REGNUM 31
264 #define context_offset(x) ((int)&(((CONTEXT *)NULL)->x))
265 static const int mappings
[] = {
266 context_offset (Eax
),
267 context_offset (Ecx
),
268 context_offset (Edx
),
269 context_offset (Ebx
),
270 context_offset (Esp
),
271 context_offset (Ebp
),
272 context_offset (Esi
),
273 context_offset (Edi
),
274 context_offset (Eip
),
275 context_offset (EFlags
),
276 context_offset (SegCs
),
277 context_offset (SegSs
),
278 context_offset (SegDs
),
279 context_offset (SegEs
),
280 context_offset (SegFs
),
281 context_offset (SegGs
),
282 context_offset (FloatSave
.RegisterArea
[0 * 10]),
283 context_offset (FloatSave
.RegisterArea
[1 * 10]),
284 context_offset (FloatSave
.RegisterArea
[2 * 10]),
285 context_offset (FloatSave
.RegisterArea
[3 * 10]),
286 context_offset (FloatSave
.RegisterArea
[4 * 10]),
287 context_offset (FloatSave
.RegisterArea
[5 * 10]),
288 context_offset (FloatSave
.RegisterArea
[6 * 10]),
289 context_offset (FloatSave
.RegisterArea
[7 * 10]),
290 context_offset (FloatSave
.ControlWord
),
291 context_offset (FloatSave
.StatusWord
),
292 context_offset (FloatSave
.TagWord
),
293 context_offset (FloatSave
.ErrorSelector
),
294 context_offset (FloatSave
.ErrorOffset
),
295 context_offset (FloatSave
.DataSelector
),
296 context_offset (FloatSave
.DataOffset
),
297 context_offset (FloatSave
.ErrorSelector
),
299 context_offset (ExtendedRegisters
[10 * 16]),
300 context_offset (ExtendedRegisters
[11 * 16]),
301 context_offset (ExtendedRegisters
[12 * 16]),
302 context_offset (ExtendedRegisters
[13 * 16]),
303 context_offset (ExtendedRegisters
[14 * 16]),
304 context_offset (ExtendedRegisters
[15 * 16]),
305 context_offset (ExtendedRegisters
[16 * 16]),
306 context_offset (ExtendedRegisters
[17 * 16]),
308 context_offset (ExtendedRegisters
[24])
311 #undef context_offset
313 /* Clear out any old thread list and reintialize it to a pristine
316 child_init_thread_list (void)
318 for_each_inferior (&all_threads
, delete_thread_info
);
322 do_initial_child_stuff (DWORD pid
)
326 last_sig
= TARGET_SIGNAL_0
;
328 debug_registers_changed
= 0;
329 debug_registers_used
= 0;
330 for (i
= 0; i
< sizeof (dr
) / sizeof (dr
[0]); i
++)
332 memset (¤t_event
, 0, sizeof (current_event
));
334 child_init_thread_list ();
337 /* Resume all artificially suspended threads if we are continuing
340 continue_one_thread (struct inferior_list_entry
*this_thread
, void *id_ptr
)
342 struct thread_info
*thread
= (struct thread_info
*) this_thread
;
343 int thread_id
= * (int *) id_ptr
;
344 thread_info
*th
= inferior_target_data (thread
);
347 if ((thread_id
== -1 || thread_id
== th
->tid
)
348 && th
->suspend_count
)
350 for (i
= 0; i
< th
->suspend_count
; i
++)
351 (void) ResumeThread (th
->h
);
352 th
->suspend_count
= 0;
353 if (debug_registers_changed
)
355 /* Only change the value of the debug registers. */
356 th
->context
.ContextFlags
= CONTEXT_DEBUG_REGISTERS
;
357 th
->context
.Dr0
= dr
[0];
358 th
->context
.Dr1
= dr
[1];
359 th
->context
.Dr2
= dr
[2];
360 th
->context
.Dr3
= dr
[3];
361 /* th->context.Dr6 = dr[6];
362 FIXME: should we set dr6 also ?? */
363 th
->context
.Dr7
= dr
[7];
364 SetThreadContext (th
->h
, &th
->context
);
365 th
->context
.ContextFlags
= 0;
373 child_continue (DWORD continue_status
, int thread_id
)
377 res
= ContinueDebugEvent (current_event
.dwProcessId
,
378 current_event
.dwThreadId
, continue_status
);
381 find_inferior (&all_threads
, continue_one_thread
, &thread_id
);
383 debug_registers_changed
= 0;
387 /* Fetch register(s) from gdbserver regcache data. */
389 do_child_fetch_inferior_registers (thread_info
*th
, int r
)
391 char *context_offset
= ((char *) &th
->context
) + mappings
[r
];
395 l
= *((long *) context_offset
) & 0xffff;
396 supply_register (r
, (char *) &l
);
398 else if (r
== FOP_REGNUM
)
400 l
= (*((long *) context_offset
) >> 16) & ((1 << 11) - 1);
401 supply_register (r
, (char *) &l
);
404 supply_register (r
, context_offset
);
407 /* Fetch register(s) from the current thread context. */
409 child_fetch_inferior_registers (int r
)
412 thread_info
*th
= thread_rec (current_inferior_tid (), TRUE
);
413 if (r
== -1 || r
== 0 || r
> NUM_REGS
)
414 child_fetch_inferior_registers (NUM_REGS
);
416 for (regno
= 0; regno
< r
; regno
++)
417 do_child_fetch_inferior_registers (th
, regno
);
420 /* Get register from gdbserver regcache data. */
422 do_child_store_inferior_registers (thread_info
*th
, int r
)
424 collect_register (r
, ((char *) &th
->context
) + mappings
[r
]);
427 /* Store a new register value into the current thread context. We don't
428 change the program's context until later, when we resume it. */
430 child_store_inferior_registers (int r
)
433 thread_info
*th
= thread_rec (current_inferior_tid (), TRUE
);
434 if (r
== -1 || r
== 0 || r
> NUM_REGS
)
435 child_store_inferior_registers (NUM_REGS
);
437 for (regno
= 0; regno
< r
; regno
++)
438 do_child_store_inferior_registers (th
, regno
);
441 /* Start a new process.
442 PROGRAM is a path to the program to execute.
443 ARGS is a standard NULL-terminated array of arguments,
444 to be passed to the inferior as ``argv''.
445 Returns the new PID on success, -1 on failure. Registers the new
446 process with the process list. */
448 win32_create_inferior (char *program
, char **program_args
)
451 char real_path
[MAXPATHLEN
];
452 char *orig_path
, *new_path
, *path_ptr
;
456 PROCESS_INFORMATION pi
;
464 error ("No executable specified, specify executable to debug.\n");
466 memset (&si
, 0, sizeof (si
));
469 flags
= DEBUG_PROCESS
| DEBUG_ONLY_THIS_PROCESS
;
473 path_ptr
= getenv ("PATH");
476 orig_path
= alloca (strlen (path_ptr
) + 1);
477 new_path
= alloca (cygwin_posix_to_win32_path_list_buf_size (path_ptr
));
478 strcpy (orig_path
, path_ptr
);
479 cygwin_posix_to_win32_path_list (path_ptr
, new_path
);
480 setenv ("PATH", new_path
, 1);
482 cygwin_conv_to_win32_path (program
, real_path
);
486 argslen
= strlen (program
) + 1;
487 for (argc
= 1; program_args
[argc
]; argc
++)
488 argslen
+= strlen (program_args
[argc
]) + 1;
489 args
= alloca (argslen
);
490 strcpy (args
, program
);
491 for (argc
= 1; program_args
[argc
]; argc
++)
493 /* FIXME: Can we do better about quoting? How does Cygwin
496 strcat (args
, program_args
[argc
]);
498 OUTMSG2 (("Command line is %s\n", args
));
500 flags
|= CREATE_NEW_PROCESS_GROUP
;
502 ret
= CreateProcess (0, args
, /* command line */
505 TRUE
, /* inherit handles */
506 flags
, /* start flags */
507 winenv
, NULL
, /* current directory */
512 setenv ("PATH", orig_path
, 1);
517 error ("Error creating process %s, (error %d): %s\n", args
,
518 (int) GetLastError (), strerror (GetLastError ()));
522 OUTMSG2 (("Process created: %s\n", (char *) args
));
525 CloseHandle (pi
.hThread
);
527 current_process_handle
= pi
.hProcess
;
528 current_process_id
= pi
.dwProcessId
;
530 do_initial_child_stuff (current_process_id
);
532 return current_process_id
;
535 /* Attach to a running process.
536 PID is the process ID to attach to, specified by the user
537 or a higher layer. */
539 win32_attach (unsigned long pid
)
542 HMODULE kernel32
= LoadLibrary ("KERNEL32.DLL");
543 winapi_DebugActiveProcessStop
*DebugActiveProcessStop
= NULL
;
544 winapi_DebugSetProcessKillOnExit
*DebugSetProcessKillOnExit
= NULL
;
546 DebugActiveProcessStop
=
547 (winapi_DebugActiveProcessStop
*) GetProcAddress (kernel32
,
548 "DebugActiveProcessStop");
549 DebugSetProcessKillOnExit
=
550 (winapi_DebugSetProcessKillOnExit
*) GetProcAddress (kernel32
,
551 "DebugSetProcessKillOnExit");
553 res
= DebugActiveProcess (pid
) ? 1 : 0;
556 error ("Attach to process failed.");
558 if (DebugSetProcessKillOnExit
!= NULL
)
559 DebugSetProcessKillOnExit (FALSE
);
561 current_process_id
= pid
;
562 current_process_handle
= OpenProcess (PROCESS_ALL_ACCESS
, FALSE
, pid
);
564 if (current_process_handle
== NULL
)
567 if (DebugActiveProcessStop
!= NULL
)
568 DebugActiveProcessStop (current_process_id
);
572 do_initial_child_stuff (pid
);
574 FreeLibrary (kernel32
);
579 /* Kill all inferiors. */
583 if (current_process_handle
== NULL
)
586 TerminateProcess (current_process_handle
, 0);
589 if (!child_continue (DBG_CONTINUE
, -1))
591 if (!WaitForDebugEvent (¤t_event
, INFINITE
))
593 if (current_event
.dwDebugEventCode
== EXIT_PROCESS_DEBUG_EVENT
)
598 /* Detach from all inferiors. */
602 HMODULE kernel32
= LoadLibrary ("KERNEL32.DLL");
603 winapi_DebugActiveProcessStop
*DebugActiveProcessStop
= NULL
;
604 winapi_DebugSetProcessKillOnExit
*DebugSetProcessKillOnExit
= NULL
;
606 DebugActiveProcessStop
=
607 (winapi_DebugActiveProcessStop
*) GetProcAddress (kernel32
,
608 "DebugActiveProcessStop");
609 DebugSetProcessKillOnExit
=
610 (winapi_DebugSetProcessKillOnExit
*) GetProcAddress (kernel32
,
611 "DebugSetProcessKillOnExit");
613 if (DebugSetProcessKillOnExit
!= NULL
)
614 DebugSetProcessKillOnExit (FALSE
);
616 if (DebugActiveProcessStop
!= NULL
)
617 DebugActiveProcessStop (current_process_id
);
621 FreeLibrary (kernel32
);
624 /* Return 1 iff the thread with thread ID TID is alive. */
626 win32_thread_alive (unsigned long tid
)
630 /* Our thread list is reliable; don't bother to poll target
632 if (find_inferior_id (&all_threads
, tid
) != NULL
)
639 /* Resume the inferior process. RESUME_INFO describes how we want
642 win32_resume (struct thread_resume
*resume_info
)
645 enum target_signal sig
;
648 DWORD continue_status
= DBG_CONTINUE
;
650 /* This handles the very limited set of resume packets that GDB can
651 currently produce. */
653 if (resume_info
[0].thread
== -1)
655 else if (resume_info
[1].thread
== -1 && !resume_info
[1].leave_stopped
)
658 /* Yes, we're ignoring resume_info[0].thread. It'd be tricky to make
659 the Windows resume code do the right thing for thread switching. */
660 tid
= current_event
.dwThreadId
;
662 if (resume_info
[0].thread
!= -1)
664 sig
= resume_info
[0].sig
;
665 step
= resume_info
[0].step
;
673 if (sig
!= TARGET_SIGNAL_0
)
675 if (current_event
.dwDebugEventCode
!= EXCEPTION_DEBUG_EVENT
)
677 OUTMSG (("Cannot continue with signal %d here.\n", sig
));
679 else if (sig
== last_sig
)
680 continue_status
= DBG_EXCEPTION_NOT_HANDLED
;
682 OUTMSG (("Can only continue with recieved signal %d.\n", last_sig
));
685 last_sig
= TARGET_SIGNAL_0
;
687 /* Get context for the currently selected thread. */
688 th
= thread_rec (current_event
.dwThreadId
, FALSE
);
691 if (th
->context
.ContextFlags
)
693 if (debug_registers_changed
)
695 th
->context
.Dr0
= dr
[0];
696 th
->context
.Dr1
= dr
[1];
697 th
->context
.Dr2
= dr
[2];
698 th
->context
.Dr3
= dr
[3];
699 /* th->context.Dr6 = dr[6];
700 FIXME: should we set dr6 also ?? */
701 th
->context
.Dr7
= dr
[7];
704 /* Move register values from the inferior into the thread
705 context structure. */
706 regcache_invalidate ();
709 th
->context
.EFlags
|= FLAG_TRACE_BIT
;
711 SetThreadContext (th
->h
, &th
->context
);
712 th
->context
.ContextFlags
= 0;
716 /* Allow continuing with the same signal that interrupted us.
717 Otherwise complain. */
719 child_continue (continue_status
, tid
);
723 handle_exception (struct target_waitstatus
*ourstatus
)
726 DWORD code
= current_event
.u
.Exception
.ExceptionRecord
.ExceptionCode
;
728 ourstatus
->kind
= TARGET_WAITKIND_STOPPED
;
730 /* Record the context of the current thread. */
731 th
= thread_rec (current_event
.dwThreadId
, -1);
735 case EXCEPTION_ACCESS_VIOLATION
:
736 OUTMSG2 (("EXCEPTION_ACCESS_VIOLATION"));
737 ourstatus
->value
.sig
= TARGET_SIGNAL_SEGV
;
739 case STATUS_STACK_OVERFLOW
:
740 OUTMSG2 (("STATUS_STACK_OVERFLOW"));
741 ourstatus
->value
.sig
= TARGET_SIGNAL_SEGV
;
743 case STATUS_FLOAT_DENORMAL_OPERAND
:
744 OUTMSG2 (("STATUS_FLOAT_DENORMAL_OPERAND"));
745 ourstatus
->value
.sig
= TARGET_SIGNAL_FPE
;
747 case EXCEPTION_ARRAY_BOUNDS_EXCEEDED
:
748 OUTMSG2 (("EXCEPTION_ARRAY_BOUNDS_EXCEEDED"));
749 ourstatus
->value
.sig
= TARGET_SIGNAL_FPE
;
751 case STATUS_FLOAT_INEXACT_RESULT
:
752 OUTMSG2 (("STATUS_FLOAT_INEXACT_RESULT"));
753 ourstatus
->value
.sig
= TARGET_SIGNAL_FPE
;
755 case STATUS_FLOAT_INVALID_OPERATION
:
756 OUTMSG2 (("STATUS_FLOAT_INVALID_OPERATION"));
757 ourstatus
->value
.sig
= TARGET_SIGNAL_FPE
;
759 case STATUS_FLOAT_OVERFLOW
:
760 OUTMSG2 (("STATUS_FLOAT_OVERFLOW"));
761 ourstatus
->value
.sig
= TARGET_SIGNAL_FPE
;
763 case STATUS_FLOAT_STACK_CHECK
:
764 OUTMSG2 (("STATUS_FLOAT_STACK_CHECK"));
765 ourstatus
->value
.sig
= TARGET_SIGNAL_FPE
;
767 case STATUS_FLOAT_UNDERFLOW
:
768 OUTMSG2 (("STATUS_FLOAT_UNDERFLOW"));
769 ourstatus
->value
.sig
= TARGET_SIGNAL_FPE
;
771 case STATUS_FLOAT_DIVIDE_BY_ZERO
:
772 OUTMSG2 (("STATUS_FLOAT_DIVIDE_BY_ZERO"));
773 ourstatus
->value
.sig
= TARGET_SIGNAL_FPE
;
775 case STATUS_INTEGER_DIVIDE_BY_ZERO
:
776 OUTMSG2 (("STATUS_INTEGER_DIVIDE_BY_ZERO"));
777 ourstatus
->value
.sig
= TARGET_SIGNAL_FPE
;
779 case STATUS_INTEGER_OVERFLOW
:
780 OUTMSG2 (("STATUS_INTEGER_OVERFLOW"));
781 ourstatus
->value
.sig
= TARGET_SIGNAL_FPE
;
783 case EXCEPTION_BREAKPOINT
:
784 OUTMSG2 (("EXCEPTION_BREAKPOINT"));
785 ourstatus
->value
.sig
= TARGET_SIGNAL_TRAP
;
788 OUTMSG2 (("DBG_CONTROL_C"));
789 ourstatus
->value
.sig
= TARGET_SIGNAL_INT
;
791 case DBG_CONTROL_BREAK
:
792 OUTMSG2 (("DBG_CONTROL_BREAK"));
793 ourstatus
->value
.sig
= TARGET_SIGNAL_INT
;
795 case EXCEPTION_SINGLE_STEP
:
796 OUTMSG2 (("EXCEPTION_SINGLE_STEP"));
797 ourstatus
->value
.sig
= TARGET_SIGNAL_TRAP
;
799 case EXCEPTION_ILLEGAL_INSTRUCTION
:
800 OUTMSG2 (("EXCEPTION_ILLEGAL_INSTRUCTION"));
801 ourstatus
->value
.sig
= TARGET_SIGNAL_ILL
;
803 case EXCEPTION_PRIV_INSTRUCTION
:
804 OUTMSG2 (("EXCEPTION_PRIV_INSTRUCTION"));
805 ourstatus
->value
.sig
= TARGET_SIGNAL_ILL
;
807 case EXCEPTION_NONCONTINUABLE_EXCEPTION
:
808 OUTMSG2 (("EXCEPTION_NONCONTINUABLE_EXCEPTION"));
809 ourstatus
->value
.sig
= TARGET_SIGNAL_ILL
;
812 if (current_event
.u
.Exception
.dwFirstChance
)
814 OUTMSG2 (("gdbserver: unknown target exception 0x%08lx at 0x%08lx",
815 current_event
.u
.Exception
.ExceptionRecord
.ExceptionCode
,
816 (DWORD
) current_event
.u
.Exception
.ExceptionRecord
.
818 ourstatus
->value
.sig
= TARGET_SIGNAL_UNKNOWN
;
822 last_sig
= ourstatus
->value
.sig
;
826 /* Get the next event from the child. Return 1 if the event requires
829 get_child_debug_event (struct target_waitstatus
*ourstatus
)
832 DWORD continue_status
, event_code
;
833 thread_info
*th
= NULL
;
834 static thread_info dummy_thread_info
;
839 last_sig
= TARGET_SIGNAL_0
;
840 ourstatus
->kind
= TARGET_WAITKIND_SPURIOUS
;
842 if (!(debug_event
= WaitForDebugEvent (¤t_event
, 1000)))
846 (struct thread_info
*) find_inferior_id (&all_threads
,
847 current_event
.dwThreadId
);
849 continue_status
= DBG_CONTINUE
;
850 event_code
= current_event
.dwDebugEventCode
;
854 case CREATE_THREAD_DEBUG_EVENT
:
855 OUTMSG2 (("gdbserver: kernel event CREATE_THREAD_DEBUG_EVENT "
856 "for pid=%d tid=%x)\n",
857 (unsigned) current_event
.dwProcessId
,
858 (unsigned) current_event
.dwThreadId
));
860 /* Record the existence of this thread. */
861 th
= child_add_thread (current_event
.dwThreadId
,
862 current_event
.u
.CreateThread
.hThread
);
864 retval
= current_event
.dwThreadId
;
867 case EXIT_THREAD_DEBUG_EVENT
:
868 OUTMSG2 (("gdbserver: kernel event EXIT_THREAD_DEBUG_EVENT "
869 "for pid=%d tid=%x\n",
870 (unsigned) current_event
.dwProcessId
,
871 (unsigned) current_event
.dwThreadId
));
872 child_delete_thread (current_event
.dwThreadId
);
873 th
= &dummy_thread_info
;
876 case CREATE_PROCESS_DEBUG_EVENT
:
877 OUTMSG2 (("gdbserver: kernel event CREATE_PROCESS_DEBUG_EVENT "
878 "for pid=%d tid=%x\n",
879 (unsigned) current_event
.dwProcessId
,
880 (unsigned) current_event
.dwThreadId
));
881 CloseHandle (current_event
.u
.CreateProcessInfo
.hFile
);
883 current_process_handle
= current_event
.u
.CreateProcessInfo
.hProcess
;
884 main_thread_id
= current_event
.dwThreadId
;
886 ourstatus
->kind
= TARGET_WAITKIND_EXECD
;
887 ourstatus
->value
.execd_pathname
= "Main executable";
889 /* Add the main thread. */
891 child_add_thread (main_thread_id
,
892 current_event
.u
.CreateProcessInfo
.hThread
);
894 retval
= ourstatus
->value
.related_pid
= current_event
.dwThreadId
;
897 case EXIT_PROCESS_DEBUG_EVENT
:
898 OUTMSG2 (("gdbserver: kernel event EXIT_PROCESS_DEBUG_EVENT "
899 "for pid=%d tid=%x\n",
900 (unsigned) current_event
.dwProcessId
,
901 (unsigned) current_event
.dwThreadId
));
902 ourstatus
->kind
= TARGET_WAITKIND_EXITED
;
903 ourstatus
->value
.integer
= current_event
.u
.ExitProcess
.dwExitCode
;
904 CloseHandle (current_process_handle
);
905 current_process_handle
= NULL
;
906 retval
= main_thread_id
;
909 case LOAD_DLL_DEBUG_EVENT
:
910 OUTMSG2 (("gdbserver: kernel event LOAD_DLL_DEBUG_EVENT "
911 "for pid=%d tid=%x\n",
912 (unsigned) current_event
.dwProcessId
,
913 (unsigned) current_event
.dwThreadId
));
914 CloseHandle (current_event
.u
.LoadDll
.hFile
);
916 ourstatus
->kind
= TARGET_WAITKIND_LOADED
;
917 ourstatus
->value
.integer
= 0;
918 retval
= main_thread_id
;
921 case UNLOAD_DLL_DEBUG_EVENT
:
922 OUTMSG2 (("gdbserver: kernel event UNLOAD_DLL_DEBUG_EVENT "
923 "for pid=%d tid=%x\n",
924 (unsigned) current_event
.dwProcessId
,
925 (unsigned) current_event
.dwThreadId
));
928 case EXCEPTION_DEBUG_EVENT
:
929 OUTMSG2 (("gdbserver: kernel event EXCEPTION_DEBUG_EVENT "
930 "for pid=%d tid=%x\n",
931 (unsigned) current_event
.dwProcessId
,
932 (unsigned) current_event
.dwThreadId
));
933 retval
= handle_exception (ourstatus
);
936 case OUTPUT_DEBUG_STRING_EVENT
:
937 /* A message from the kernel (or Cygwin). */
938 OUTMSG2 (("gdbserver: kernel event OUTPUT_DEBUG_STRING_EVENT "
939 "for pid=%d tid=%x\n",
940 (unsigned) current_event
.dwProcessId
,
941 (unsigned) current_event
.dwThreadId
));
945 OUTMSG2 (("gdbserver: kernel event unknown "
946 "for pid=%d tid=%x code=%ld\n",
947 (unsigned) current_event
.dwProcessId
,
948 (unsigned) current_event
.dwThreadId
,
949 current_event
.dwDebugEventCode
));
954 (struct thread_info
*) find_inferior_id (&all_threads
,
955 current_event
.dwThreadId
);
957 if (!retval
|| (event_code
!= EXCEPTION_DEBUG_EVENT
&& event_code
!= EXIT_PROCESS_DEBUG_EVENT
))
959 child_continue (continue_status
, -1);
964 thread_rec (current_event
.dwThreadId
, TRUE
);
970 /* Wait for the inferior process to change state.
971 STATUS will be filled in with a response code to send to GDB.
972 Returns the signal which caused the process to stop. */
974 win32_wait (char *status
)
976 struct target_waitstatus our_status
;
982 get_child_debug_event (&our_status
);
984 if (our_status
.kind
== TARGET_WAITKIND_EXITED
)
986 OUTMSG2 (("Child exited with retcode = %x\n",
987 our_status
.value
.integer
));
991 child_fetch_inferior_registers (-1);
993 return our_status
.value
.integer
;
995 else if (our_status
.kind
== TARGET_WAITKIND_STOPPED
)
997 OUTMSG2 (("Child Stopped with signal = %x \n",
998 WSTOPSIG (our_status
.value
.sig
)));
1002 child_fetch_inferior_registers (-1);
1004 return our_status
.value
.sig
;
1007 OUTMSG (("Ignoring unknown internal event, %d\n", our_status
.kind
));
1010 struct thread_resume resume
;
1014 resume
.leave_stopped
= 0;
1015 win32_resume (&resume
);
1020 /* Fetch registers from the inferior process.
1021 If REGNO is -1, fetch all registers; otherwise, fetch at least REGNO. */
1023 win32_fetch_inferior_registers (int regno
)
1025 child_fetch_inferior_registers (regno
);
1028 /* Store registers to the inferior process.
1029 If REGNO is -1, store all registers; otherwise, store at least REGNO. */
1031 win32_store_inferior_registers (int regno
)
1033 child_store_inferior_registers (regno
);
1036 /* Read memory from the inferior process. This should generally be
1037 called through read_inferior_memory, which handles breakpoint shadowing.
1038 Read LEN bytes at MEMADDR into a buffer at MYADDR. */
1040 win32_read_inferior_memory (CORE_ADDR memaddr
, unsigned char *myaddr
, int len
)
1042 return child_xfer_memory (memaddr
, myaddr
, len
, 0, 0) != len
;
1045 /* Write memory to the inferior process. This should generally be
1046 called through write_inferior_memory, which handles breakpoint shadowing.
1047 Write LEN bytes from the buffer at MYADDR to MEMADDR.
1048 Returns 0 on success and errno on failure. */
1050 win32_write_inferior_memory (CORE_ADDR memaddr
, const unsigned char *myaddr
,
1053 return child_xfer_memory (memaddr
, (char *) myaddr
, len
, 1, 0) != len
;
1057 win32_arch_string (void)
1062 static struct target_ops win32_target_ops
= {
1063 win32_create_inferior
,
1070 win32_fetch_inferior_registers
,
1071 win32_store_inferior_registers
,
1072 win32_read_inferior_memory
,
1073 win32_write_inferior_memory
,
1086 /* Initialize the Win32 backend. */
1088 initialize_low (void)
1090 set_target_ops (&win32_target_ops
);