1 /* Low level interface to Windows debugging, for gdbserver.
3 Free Software Foundation, Inc.
5 Contributed by Leo Zayas. Based on "win32-nat.c" from GDB.
7 This file is part of GDB.
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 51 Franklin Street, Fifth Floor,
22 Boston, MA 02110-1301, USA. */
26 #include "gdb/signals.h"
31 #include <sys/param.h>
36 #include <sys/cygwin.h>
41 #define OUTMSG(X) do { printf X; fflush (stdout); } while (0)
43 #define OUTMSG2(X) do { printf X; fflush (stdout); } while (0)
49 int using_threads
= 1;
52 static HANDLE current_process_handle
= NULL
;
53 static DWORD current_process_id
= 0;
54 static enum target_signal last_sig
= TARGET_SIGNAL_0
;
56 /* The current debug event from WaitForDebugEvent. */
57 static DEBUG_EVENT current_event
;
59 static int debug_registers_changed
= 0;
60 static int debug_registers_used
= 0;
61 static unsigned dr
[8];
63 typedef BOOL
winapi_DebugActiveProcessStop (DWORD dwProcessId
);
64 typedef BOOL
winapi_DebugSetProcessKillOnExit (BOOL KillOnExit
);
66 #define FLAG_TRACE_BIT 0x100
67 #define CONTEXT_DEBUGGER (CONTEXT_FULL | CONTEXT_FLOATING_POINT)
68 #define CONTEXT_DEBUGGER_DR CONTEXT_DEBUGGER | CONTEXT_DEBUG_REGISTERS \
69 | CONTEXT_EXTENDED_REGISTERS
71 /* Thread information structure used to track extra information about
73 typedef struct thread_info_struct
80 static DWORD main_thread_id
= 0;
82 /* Get the thread ID from the current selected inferior (the current
85 current_inferior_tid (void)
87 thread_info
*th
= inferior_target_data (current_inferior
);
91 /* Find a thread record given a thread id. If GET_CONTEXT is set then
92 also retrieve the context for this thread. */
94 thread_rec (DWORD id
, int get_context
)
96 struct thread_info
*thread
;
99 thread
= (struct thread_info
*) find_inferior_id (&all_threads
, id
);
103 th
= inferior_target_data (thread
);
104 if (!th
->suspend_count
&& get_context
)
106 if (get_context
> 0 && id
!= current_event
.dwThreadId
)
107 th
->suspend_count
= SuspendThread (th
->h
) + 1;
108 else if (get_context
< 0)
109 th
->suspend_count
= -1;
111 th
->context
.ContextFlags
= CONTEXT_DEBUGGER_DR
;
113 GetThreadContext (th
->h
, &th
->context
);
115 if (id
== current_event
.dwThreadId
)
117 /* Copy dr values from that thread. */
118 dr
[0] = th
->context
.Dr0
;
119 dr
[1] = th
->context
.Dr1
;
120 dr
[2] = th
->context
.Dr2
;
121 dr
[3] = th
->context
.Dr3
;
122 dr
[6] = th
->context
.Dr6
;
123 dr
[7] = th
->context
.Dr7
;
130 /* Add a thread to the thread list. */
132 child_add_thread (DWORD tid
, HANDLE h
)
136 if ((th
= thread_rec (tid
, FALSE
)))
139 th
= (thread_info
*) malloc (sizeof (*th
));
140 memset (th
, 0, sizeof (*th
));
144 add_thread (tid
, th
, (unsigned int) tid
);
145 set_inferior_regcache_data ((struct thread_info
*)
146 find_inferior_id (&all_threads
, tid
),
147 new_register_cache ());
149 /* Set the debug registers for the new thread if they are used. */
150 if (debug_registers_used
)
152 /* Only change the value of the debug registers. */
153 th
->context
.ContextFlags
= CONTEXT_DEBUGGER_DR
;
155 GetThreadContext (th
->h
, &th
->context
);
157 th
->context
.Dr0
= dr
[0];
158 th
->context
.Dr1
= dr
[1];
159 th
->context
.Dr2
= dr
[2];
160 th
->context
.Dr3
= dr
[3];
161 /* th->context.Dr6 = dr[6];
162 FIXME: should we set dr6 also ?? */
163 th
->context
.Dr7
= dr
[7];
164 SetThreadContext (th
->h
, &th
->context
);
165 th
->context
.ContextFlags
= 0;
171 /* Delete a thread from the list of threads. */
173 delete_thread_info (struct inferior_list_entry
*thread
)
175 thread_info
*th
= inferior_target_data ((struct thread_info
*) thread
);
177 remove_thread ((struct thread_info
*) thread
);
182 /* Delete a thread from the list of threads. */
184 child_delete_thread (DWORD id
)
186 struct inferior_list_entry
*thread
;
188 /* If the last thread is exiting, just return. */
189 if (all_threads
.head
== all_threads
.tail
)
192 thread
= find_inferior_id (&all_threads
, id
);
196 delete_thread_info (thread
);
199 /* Transfer memory from/to the debugged process. */
201 child_xfer_memory (CORE_ADDR memaddr
, char *our
, int len
,
202 int write
, struct target_ops
*target
)
205 long addr
= (long) memaddr
;
209 WriteProcessMemory (current_process_handle
, (LPVOID
) addr
,
210 (LPCVOID
) our
, len
, &done
);
211 FlushInstructionCache (current_process_handle
, (LPCVOID
) addr
, len
);
215 ReadProcessMemory (current_process_handle
, (LPCVOID
) addr
, (LPVOID
) our
,
221 /* Generally, what has the program done? */
224 /* The program has exited. The exit status is in value.integer. */
225 TARGET_WAITKIND_EXITED
,
227 /* The program has stopped with a signal. Which signal is in
229 TARGET_WAITKIND_STOPPED
,
231 /* The program is letting us know that it dynamically loaded something
232 (e.g. it called load(2) on AIX). */
233 TARGET_WAITKIND_LOADED
,
235 /* The program has exec'ed a new executable file. The new file's
236 pathname is pointed to by value.execd_pathname. */
238 TARGET_WAITKIND_EXECD
,
240 /* Nothing happened, but we stopped anyway. This perhaps should be handled
241 within target_wait, but I'm not sure target_wait should be resuming the
243 TARGET_WAITKIND_SPURIOUS
,
246 struct target_waitstatus
248 enum target_waitkind kind
;
250 /* Forked child pid, execd pathname, exit status or signal number. */
254 enum target_signal sig
;
256 char *execd_pathname
;
263 #define FCS_REGNUM 27
264 #define FOP_REGNUM 31
266 #define context_offset(x) ((int)&(((CONTEXT *)NULL)->x))
267 static const int mappings
[] = {
268 context_offset (Eax
),
269 context_offset (Ecx
),
270 context_offset (Edx
),
271 context_offset (Ebx
),
272 context_offset (Esp
),
273 context_offset (Ebp
),
274 context_offset (Esi
),
275 context_offset (Edi
),
276 context_offset (Eip
),
277 context_offset (EFlags
),
278 context_offset (SegCs
),
279 context_offset (SegSs
),
280 context_offset (SegDs
),
281 context_offset (SegEs
),
282 context_offset (SegFs
),
283 context_offset (SegGs
),
284 context_offset (FloatSave
.RegisterArea
[0 * 10]),
285 context_offset (FloatSave
.RegisterArea
[1 * 10]),
286 context_offset (FloatSave
.RegisterArea
[2 * 10]),
287 context_offset (FloatSave
.RegisterArea
[3 * 10]),
288 context_offset (FloatSave
.RegisterArea
[4 * 10]),
289 context_offset (FloatSave
.RegisterArea
[5 * 10]),
290 context_offset (FloatSave
.RegisterArea
[6 * 10]),
291 context_offset (FloatSave
.RegisterArea
[7 * 10]),
292 context_offset (FloatSave
.ControlWord
),
293 context_offset (FloatSave
.StatusWord
),
294 context_offset (FloatSave
.TagWord
),
295 context_offset (FloatSave
.ErrorSelector
),
296 context_offset (FloatSave
.ErrorOffset
),
297 context_offset (FloatSave
.DataSelector
),
298 context_offset (FloatSave
.DataOffset
),
299 context_offset (FloatSave
.ErrorSelector
),
301 context_offset (ExtendedRegisters
[10 * 16]),
302 context_offset (ExtendedRegisters
[11 * 16]),
303 context_offset (ExtendedRegisters
[12 * 16]),
304 context_offset (ExtendedRegisters
[13 * 16]),
305 context_offset (ExtendedRegisters
[14 * 16]),
306 context_offset (ExtendedRegisters
[15 * 16]),
307 context_offset (ExtendedRegisters
[16 * 16]),
308 context_offset (ExtendedRegisters
[17 * 16]),
310 context_offset (ExtendedRegisters
[24])
313 #undef context_offset
315 /* Clear out any old thread list and reintialize it to a pristine
318 child_init_thread_list (void)
320 for_each_inferior (&all_threads
, delete_thread_info
);
324 do_initial_child_stuff (DWORD pid
)
328 last_sig
= TARGET_SIGNAL_0
;
330 debug_registers_changed
= 0;
331 debug_registers_used
= 0;
332 for (i
= 0; i
< sizeof (dr
) / sizeof (dr
[0]); i
++)
334 memset (¤t_event
, 0, sizeof (current_event
));
336 child_init_thread_list ();
339 /* Resume all artificially suspended threads if we are continuing
342 continue_one_thread (struct inferior_list_entry
*this_thread
, void *id_ptr
)
344 struct thread_info
*thread
= (struct thread_info
*) this_thread
;
345 int thread_id
= * (int *) id_ptr
;
346 thread_info
*th
= inferior_target_data (thread
);
349 if ((thread_id
== -1 || thread_id
== th
->tid
)
350 && th
->suspend_count
)
352 for (i
= 0; i
< th
->suspend_count
; i
++)
353 (void) ResumeThread (th
->h
);
354 th
->suspend_count
= 0;
355 if (debug_registers_changed
)
357 /* Only change the value of the debug registers. */
358 th
->context
.ContextFlags
= CONTEXT_DEBUG_REGISTERS
;
359 th
->context
.Dr0
= dr
[0];
360 th
->context
.Dr1
= dr
[1];
361 th
->context
.Dr2
= dr
[2];
362 th
->context
.Dr3
= dr
[3];
363 /* th->context.Dr6 = dr[6];
364 FIXME: should we set dr6 also ?? */
365 th
->context
.Dr7
= dr
[7];
366 SetThreadContext (th
->h
, &th
->context
);
367 th
->context
.ContextFlags
= 0;
375 child_continue (DWORD continue_status
, int thread_id
)
379 res
= ContinueDebugEvent (current_event
.dwProcessId
,
380 current_event
.dwThreadId
, continue_status
);
383 find_inferior (&all_threads
, continue_one_thread
, &thread_id
);
385 debug_registers_changed
= 0;
389 /* Fetch register(s) from gdbserver regcache data. */
391 do_child_fetch_inferior_registers (thread_info
*th
, int r
)
393 char *context_offset
= ((char *) &th
->context
) + mappings
[r
];
397 l
= *((long *) context_offset
) & 0xffff;
398 supply_register (r
, (char *) &l
);
400 else if (r
== FOP_REGNUM
)
402 l
= (*((long *) context_offset
) >> 16) & ((1 << 11) - 1);
403 supply_register (r
, (char *) &l
);
406 supply_register (r
, context_offset
);
409 /* Fetch register(s) from the current thread context. */
411 child_fetch_inferior_registers (int r
)
414 thread_info
*th
= thread_rec (current_inferior_tid (), TRUE
);
415 if (r
== -1 || r
== 0 || r
> NUM_REGS
)
416 child_fetch_inferior_registers (NUM_REGS
);
418 for (regno
= 0; regno
< r
; regno
++)
419 do_child_fetch_inferior_registers (th
, regno
);
422 /* Get register from gdbserver regcache data. */
424 do_child_store_inferior_registers (thread_info
*th
, int r
)
426 collect_register (r
, ((char *) &th
->context
) + mappings
[r
]);
429 /* Store a new register value into the current thread context. We don't
430 change the program's context until later, when we resume it. */
432 child_store_inferior_registers (int r
)
435 thread_info
*th
= thread_rec (current_inferior_tid (), TRUE
);
436 if (r
== -1 || r
== 0 || r
> NUM_REGS
)
437 child_store_inferior_registers (NUM_REGS
);
439 for (regno
= 0; regno
< r
; regno
++)
440 do_child_store_inferior_registers (th
, regno
);
443 /* Start a new process.
444 PROGRAM is a path to the program to execute.
445 ARGS is a standard NULL-terminated array of arguments,
446 to be passed to the inferior as ``argv''.
447 Returns the new PID on success, -1 on failure. Registers the new
448 process with the process list. */
450 win32_create_inferior (char *program
, char **program_args
)
453 char real_path
[MAXPATHLEN
];
454 char *orig_path
, *new_path
, *path_ptr
;
458 PROCESS_INFORMATION pi
;
466 error ("No executable specified, specify executable to debug.\n");
468 memset (&si
, 0, sizeof (si
));
471 flags
= DEBUG_PROCESS
| DEBUG_ONLY_THIS_PROCESS
;
475 path_ptr
= getenv ("PATH");
478 orig_path
= alloca (strlen (path_ptr
) + 1);
479 new_path
= alloca (cygwin_posix_to_win32_path_list_buf_size (path_ptr
));
480 strcpy (orig_path
, path_ptr
);
481 cygwin_posix_to_win32_path_list (path_ptr
, new_path
);
482 setenv ("PATH", new_path
, 1);
484 cygwin_conv_to_win32_path (program
, real_path
);
488 argslen
= strlen (program
) + 1;
489 for (argc
= 1; program_args
[argc
]; argc
++)
490 argslen
+= strlen (program_args
[argc
]) + 1;
491 args
= alloca (argslen
);
492 strcpy (args
, program
);
493 for (argc
= 1; program_args
[argc
]; argc
++)
495 /* FIXME: Can we do better about quoting? How does Cygwin
498 strcat (args
, program_args
[argc
]);
500 OUTMSG2 (("Command line is %s\n", args
));
502 flags
|= CREATE_NEW_PROCESS_GROUP
;
504 ret
= CreateProcess (0, args
, /* command line */
507 TRUE
, /* inherit handles */
508 flags
, /* start flags */
509 winenv
, NULL
, /* current directory */
514 setenv ("PATH", orig_path
, 1);
519 error ("Error creating process %s, (error %d): %s\n", args
,
520 (int) GetLastError (), strerror (GetLastError ()));
524 OUTMSG2 (("Process created: %s\n", (char *) args
));
527 CloseHandle (pi
.hThread
);
529 current_process_handle
= pi
.hProcess
;
530 current_process_id
= pi
.dwProcessId
;
532 do_initial_child_stuff (current_process_id
);
534 return current_process_id
;
537 /* Attach to a running process.
538 PID is the process ID to attach to, specified by the user
539 or a higher layer. */
541 win32_attach (unsigned long pid
)
544 HMODULE kernel32
= LoadLibrary ("KERNEL32.DLL");
545 winapi_DebugActiveProcessStop
*DebugActiveProcessStop
= NULL
;
546 winapi_DebugSetProcessKillOnExit
*DebugSetProcessKillOnExit
= NULL
;
548 DebugActiveProcessStop
=
549 (winapi_DebugActiveProcessStop
*) GetProcAddress (kernel32
,
550 "DebugActiveProcessStop");
551 DebugSetProcessKillOnExit
=
552 (winapi_DebugSetProcessKillOnExit
*) GetProcAddress (kernel32
,
553 "DebugSetProcessKillOnExit");
555 res
= DebugActiveProcess (pid
) ? 1 : 0;
558 error ("Attach to process failed.");
560 if (DebugSetProcessKillOnExit
!= NULL
)
561 DebugSetProcessKillOnExit (FALSE
);
563 current_process_id
= pid
;
564 current_process_handle
= OpenProcess (PROCESS_ALL_ACCESS
, FALSE
, pid
);
566 if (current_process_handle
== NULL
)
569 if (DebugActiveProcessStop
!= NULL
)
570 DebugActiveProcessStop (current_process_id
);
574 do_initial_child_stuff (pid
);
576 FreeLibrary (kernel32
);
581 /* Kill all inferiors. */
585 if (current_process_handle
== NULL
)
588 TerminateProcess (current_process_handle
, 0);
591 if (!child_continue (DBG_CONTINUE
, -1))
593 if (!WaitForDebugEvent (¤t_event
, INFINITE
))
595 if (current_event
.dwDebugEventCode
== EXIT_PROCESS_DEBUG_EVENT
)
600 /* Detach from all inferiors. */
604 HMODULE kernel32
= LoadLibrary ("KERNEL32.DLL");
605 winapi_DebugActiveProcessStop
*DebugActiveProcessStop
= NULL
;
606 winapi_DebugSetProcessKillOnExit
*DebugSetProcessKillOnExit
= NULL
;
608 DebugActiveProcessStop
=
609 (winapi_DebugActiveProcessStop
*) GetProcAddress (kernel32
,
610 "DebugActiveProcessStop");
611 DebugSetProcessKillOnExit
=
612 (winapi_DebugSetProcessKillOnExit
*) GetProcAddress (kernel32
,
613 "DebugSetProcessKillOnExit");
615 if (DebugSetProcessKillOnExit
!= NULL
)
616 DebugSetProcessKillOnExit (FALSE
);
618 if (DebugActiveProcessStop
!= NULL
)
619 DebugActiveProcessStop (current_process_id
);
623 FreeLibrary (kernel32
);
626 /* Return 1 iff the thread with thread ID TID is alive. */
628 win32_thread_alive (unsigned long tid
)
632 /* Our thread list is reliable; don't bother to poll target
634 if (find_inferior_id (&all_threads
, tid
) != NULL
)
641 /* Resume the inferior process. RESUME_INFO describes how we want
644 win32_resume (struct thread_resume
*resume_info
)
647 enum target_signal sig
;
650 DWORD continue_status
= DBG_CONTINUE
;
652 /* This handles the very limited set of resume packets that GDB can
653 currently produce. */
655 if (resume_info
[0].thread
== -1)
657 else if (resume_info
[1].thread
== -1 && !resume_info
[1].leave_stopped
)
660 /* Yes, we're ignoring resume_info[0].thread. It'd be tricky to make
661 the Windows resume code do the right thing for thread switching. */
662 tid
= current_event
.dwThreadId
;
664 if (resume_info
[0].thread
!= -1)
666 sig
= resume_info
[0].sig
;
667 step
= resume_info
[0].step
;
675 if (sig
!= TARGET_SIGNAL_0
)
677 if (current_event
.dwDebugEventCode
!= EXCEPTION_DEBUG_EVENT
)
679 OUTMSG (("Cannot continue with signal %d here.\n", sig
));
681 else if (sig
== last_sig
)
682 continue_status
= DBG_EXCEPTION_NOT_HANDLED
;
684 OUTMSG (("Can only continue with recieved signal %d.\n", last_sig
));
687 last_sig
= TARGET_SIGNAL_0
;
689 /* Get context for the currently selected thread. */
690 th
= thread_rec (current_event
.dwThreadId
, FALSE
);
693 if (th
->context
.ContextFlags
)
695 if (debug_registers_changed
)
697 th
->context
.Dr0
= dr
[0];
698 th
->context
.Dr1
= dr
[1];
699 th
->context
.Dr2
= dr
[2];
700 th
->context
.Dr3
= dr
[3];
701 /* th->context.Dr6 = dr[6];
702 FIXME: should we set dr6 also ?? */
703 th
->context
.Dr7
= dr
[7];
706 /* Move register values from the inferior into the thread
707 context structure. */
708 regcache_invalidate ();
711 th
->context
.EFlags
|= FLAG_TRACE_BIT
;
713 SetThreadContext (th
->h
, &th
->context
);
714 th
->context
.ContextFlags
= 0;
718 /* Allow continuing with the same signal that interrupted us.
719 Otherwise complain. */
721 child_continue (continue_status
, tid
);
725 handle_exception (struct target_waitstatus
*ourstatus
)
728 DWORD code
= current_event
.u
.Exception
.ExceptionRecord
.ExceptionCode
;
730 ourstatus
->kind
= TARGET_WAITKIND_STOPPED
;
732 /* Record the context of the current thread. */
733 th
= thread_rec (current_event
.dwThreadId
, -1);
737 case EXCEPTION_ACCESS_VIOLATION
:
738 OUTMSG2 (("EXCEPTION_ACCESS_VIOLATION"));
739 ourstatus
->value
.sig
= TARGET_SIGNAL_SEGV
;
741 case STATUS_STACK_OVERFLOW
:
742 OUTMSG2 (("STATUS_STACK_OVERFLOW"));
743 ourstatus
->value
.sig
= TARGET_SIGNAL_SEGV
;
745 case STATUS_FLOAT_DENORMAL_OPERAND
:
746 OUTMSG2 (("STATUS_FLOAT_DENORMAL_OPERAND"));
747 ourstatus
->value
.sig
= TARGET_SIGNAL_FPE
;
749 case EXCEPTION_ARRAY_BOUNDS_EXCEEDED
:
750 OUTMSG2 (("EXCEPTION_ARRAY_BOUNDS_EXCEEDED"));
751 ourstatus
->value
.sig
= TARGET_SIGNAL_FPE
;
753 case STATUS_FLOAT_INEXACT_RESULT
:
754 OUTMSG2 (("STATUS_FLOAT_INEXACT_RESULT"));
755 ourstatus
->value
.sig
= TARGET_SIGNAL_FPE
;
757 case STATUS_FLOAT_INVALID_OPERATION
:
758 OUTMSG2 (("STATUS_FLOAT_INVALID_OPERATION"));
759 ourstatus
->value
.sig
= TARGET_SIGNAL_FPE
;
761 case STATUS_FLOAT_OVERFLOW
:
762 OUTMSG2 (("STATUS_FLOAT_OVERFLOW"));
763 ourstatus
->value
.sig
= TARGET_SIGNAL_FPE
;
765 case STATUS_FLOAT_STACK_CHECK
:
766 OUTMSG2 (("STATUS_FLOAT_STACK_CHECK"));
767 ourstatus
->value
.sig
= TARGET_SIGNAL_FPE
;
769 case STATUS_FLOAT_UNDERFLOW
:
770 OUTMSG2 (("STATUS_FLOAT_UNDERFLOW"));
771 ourstatus
->value
.sig
= TARGET_SIGNAL_FPE
;
773 case STATUS_FLOAT_DIVIDE_BY_ZERO
:
774 OUTMSG2 (("STATUS_FLOAT_DIVIDE_BY_ZERO"));
775 ourstatus
->value
.sig
= TARGET_SIGNAL_FPE
;
777 case STATUS_INTEGER_DIVIDE_BY_ZERO
:
778 OUTMSG2 (("STATUS_INTEGER_DIVIDE_BY_ZERO"));
779 ourstatus
->value
.sig
= TARGET_SIGNAL_FPE
;
781 case STATUS_INTEGER_OVERFLOW
:
782 OUTMSG2 (("STATUS_INTEGER_OVERFLOW"));
783 ourstatus
->value
.sig
= TARGET_SIGNAL_FPE
;
785 case EXCEPTION_BREAKPOINT
:
786 OUTMSG2 (("EXCEPTION_BREAKPOINT"));
787 ourstatus
->value
.sig
= TARGET_SIGNAL_TRAP
;
790 OUTMSG2 (("DBG_CONTROL_C"));
791 ourstatus
->value
.sig
= TARGET_SIGNAL_INT
;
793 case DBG_CONTROL_BREAK
:
794 OUTMSG2 (("DBG_CONTROL_BREAK"));
795 ourstatus
->value
.sig
= TARGET_SIGNAL_INT
;
797 case EXCEPTION_SINGLE_STEP
:
798 OUTMSG2 (("EXCEPTION_SINGLE_STEP"));
799 ourstatus
->value
.sig
= TARGET_SIGNAL_TRAP
;
801 case EXCEPTION_ILLEGAL_INSTRUCTION
:
802 OUTMSG2 (("EXCEPTION_ILLEGAL_INSTRUCTION"));
803 ourstatus
->value
.sig
= TARGET_SIGNAL_ILL
;
805 case EXCEPTION_PRIV_INSTRUCTION
:
806 OUTMSG2 (("EXCEPTION_PRIV_INSTRUCTION"));
807 ourstatus
->value
.sig
= TARGET_SIGNAL_ILL
;
809 case EXCEPTION_NONCONTINUABLE_EXCEPTION
:
810 OUTMSG2 (("EXCEPTION_NONCONTINUABLE_EXCEPTION"));
811 ourstatus
->value
.sig
= TARGET_SIGNAL_ILL
;
814 if (current_event
.u
.Exception
.dwFirstChance
)
816 OUTMSG2 (("gdbserver: unknown target exception 0x%08lx at 0x%08lx",
817 current_event
.u
.Exception
.ExceptionRecord
.ExceptionCode
,
818 (DWORD
) current_event
.u
.Exception
.ExceptionRecord
.
820 ourstatus
->value
.sig
= TARGET_SIGNAL_UNKNOWN
;
824 last_sig
= ourstatus
->value
.sig
;
828 /* Get the next event from the child. Return 1 if the event requires
831 get_child_debug_event (struct target_waitstatus
*ourstatus
)
834 DWORD continue_status
, event_code
;
835 thread_info
*th
= NULL
;
836 static thread_info dummy_thread_info
;
841 last_sig
= TARGET_SIGNAL_0
;
842 ourstatus
->kind
= TARGET_WAITKIND_SPURIOUS
;
844 if (!(debug_event
= WaitForDebugEvent (¤t_event
, 1000)))
848 (struct thread_info
*) find_inferior_id (&all_threads
,
849 current_event
.dwThreadId
);
851 continue_status
= DBG_CONTINUE
;
852 event_code
= current_event
.dwDebugEventCode
;
856 case CREATE_THREAD_DEBUG_EVENT
:
857 OUTMSG2 (("gdbserver: kernel event CREATE_THREAD_DEBUG_EVENT "
858 "for pid=%d tid=%x)\n",
859 (unsigned) current_event
.dwProcessId
,
860 (unsigned) current_event
.dwThreadId
));
862 /* Record the existence of this thread. */
863 th
= child_add_thread (current_event
.dwThreadId
,
864 current_event
.u
.CreateThread
.hThread
);
866 retval
= current_event
.dwThreadId
;
869 case EXIT_THREAD_DEBUG_EVENT
:
870 OUTMSG2 (("gdbserver: kernel event EXIT_THREAD_DEBUG_EVENT "
871 "for pid=%d tid=%x\n",
872 (unsigned) current_event
.dwProcessId
,
873 (unsigned) current_event
.dwThreadId
));
874 child_delete_thread (current_event
.dwThreadId
);
875 th
= &dummy_thread_info
;
878 case CREATE_PROCESS_DEBUG_EVENT
:
879 OUTMSG2 (("gdbserver: kernel event CREATE_PROCESS_DEBUG_EVENT "
880 "for pid=%d tid=%x\n",
881 (unsigned) current_event
.dwProcessId
,
882 (unsigned) current_event
.dwThreadId
));
883 CloseHandle (current_event
.u
.CreateProcessInfo
.hFile
);
885 current_process_handle
= current_event
.u
.CreateProcessInfo
.hProcess
;
886 main_thread_id
= current_event
.dwThreadId
;
888 ourstatus
->kind
= TARGET_WAITKIND_EXECD
;
889 ourstatus
->value
.execd_pathname
= "Main executable";
891 /* Add the main thread. */
893 child_add_thread (main_thread_id
,
894 current_event
.u
.CreateProcessInfo
.hThread
);
896 retval
= ourstatus
->value
.related_pid
= current_event
.dwThreadId
;
899 case EXIT_PROCESS_DEBUG_EVENT
:
900 OUTMSG2 (("gdbserver: kernel event EXIT_PROCESS_DEBUG_EVENT "
901 "for pid=%d tid=%x\n",
902 (unsigned) current_event
.dwProcessId
,
903 (unsigned) current_event
.dwThreadId
));
904 ourstatus
->kind
= TARGET_WAITKIND_EXITED
;
905 ourstatus
->value
.integer
= current_event
.u
.ExitProcess
.dwExitCode
;
906 CloseHandle (current_process_handle
);
907 current_process_handle
= NULL
;
908 retval
= main_thread_id
;
911 case LOAD_DLL_DEBUG_EVENT
:
912 OUTMSG2 (("gdbserver: kernel event LOAD_DLL_DEBUG_EVENT "
913 "for pid=%d tid=%x\n",
914 (unsigned) current_event
.dwProcessId
,
915 (unsigned) current_event
.dwThreadId
));
916 CloseHandle (current_event
.u
.LoadDll
.hFile
);
918 ourstatus
->kind
= TARGET_WAITKIND_LOADED
;
919 ourstatus
->value
.integer
= 0;
920 retval
= main_thread_id
;
923 case UNLOAD_DLL_DEBUG_EVENT
:
924 OUTMSG2 (("gdbserver: kernel event UNLOAD_DLL_DEBUG_EVENT "
925 "for pid=%d tid=%x\n",
926 (unsigned) current_event
.dwProcessId
,
927 (unsigned) current_event
.dwThreadId
));
930 case EXCEPTION_DEBUG_EVENT
:
931 OUTMSG2 (("gdbserver: kernel event EXCEPTION_DEBUG_EVENT "
932 "for pid=%d tid=%x\n",
933 (unsigned) current_event
.dwProcessId
,
934 (unsigned) current_event
.dwThreadId
));
935 retval
= handle_exception (ourstatus
);
938 case OUTPUT_DEBUG_STRING_EVENT
:
939 /* A message from the kernel (or Cygwin). */
940 OUTMSG2 (("gdbserver: kernel event OUTPUT_DEBUG_STRING_EVENT "
941 "for pid=%d tid=%x\n",
942 (unsigned) current_event
.dwProcessId
,
943 (unsigned) current_event
.dwThreadId
));
947 OUTMSG2 (("gdbserver: kernel event unknown "
948 "for pid=%d tid=%x code=%ld\n",
949 (unsigned) current_event
.dwProcessId
,
950 (unsigned) current_event
.dwThreadId
,
951 current_event
.dwDebugEventCode
));
956 (struct thread_info
*) find_inferior_id (&all_threads
,
957 current_event
.dwThreadId
);
959 if (!retval
|| (event_code
!= EXCEPTION_DEBUG_EVENT
&& event_code
!= EXIT_PROCESS_DEBUG_EVENT
))
961 child_continue (continue_status
, -1);
966 thread_rec (current_event
.dwThreadId
, TRUE
);
972 /* Wait for the inferior process to change state.
973 STATUS will be filled in with a response code to send to GDB.
974 Returns the signal which caused the process to stop. */
976 win32_wait (char *status
)
978 struct target_waitstatus our_status
;
984 get_child_debug_event (&our_status
);
986 if (our_status
.kind
== TARGET_WAITKIND_EXITED
)
988 OUTMSG2 (("Child exited with retcode = %x\n",
989 our_status
.value
.integer
));
993 child_fetch_inferior_registers (-1);
995 return our_status
.value
.integer
;
997 else if (our_status
.kind
== TARGET_WAITKIND_STOPPED
)
999 OUTMSG2 (("Child Stopped with signal = %x \n",
1000 WSTOPSIG (our_status
.value
.sig
)));
1004 child_fetch_inferior_registers (-1);
1006 return our_status
.value
.sig
;
1009 OUTMSG (("Ignoring unknown internal event, %d\n", our_status
.kind
));
1012 struct thread_resume resume
;
1016 resume
.leave_stopped
= 0;
1017 win32_resume (&resume
);
1022 /* Fetch registers from the inferior process.
1023 If REGNO is -1, fetch all registers; otherwise, fetch at least REGNO. */
1025 win32_fetch_inferior_registers (int regno
)
1027 child_fetch_inferior_registers (regno
);
1030 /* Store registers to the inferior process.
1031 If REGNO is -1, store all registers; otherwise, store at least REGNO. */
1033 win32_store_inferior_registers (int regno
)
1035 child_store_inferior_registers (regno
);
1038 /* Read memory from the inferior process. This should generally be
1039 called through read_inferior_memory, which handles breakpoint shadowing.
1040 Read LEN bytes at MEMADDR into a buffer at MYADDR. */
1042 win32_read_inferior_memory (CORE_ADDR memaddr
, unsigned char *myaddr
, int len
)
1044 return child_xfer_memory (memaddr
, myaddr
, len
, 0, 0) != len
;
1047 /* Write memory to the inferior process. This should generally be
1048 called through write_inferior_memory, which handles breakpoint shadowing.
1049 Write LEN bytes from the buffer at MYADDR to MEMADDR.
1050 Returns 0 on success and errno on failure. */
1052 win32_write_inferior_memory (CORE_ADDR memaddr
, const unsigned char *myaddr
,
1055 return child_xfer_memory (memaddr
, (char *) myaddr
, len
, 1, 0) != len
;
1058 static struct target_ops win32_target_ops
= {
1059 win32_create_inferior
,
1066 win32_fetch_inferior_registers
,
1067 win32_store_inferior_registers
,
1068 win32_read_inferior_memory
,
1069 win32_write_inferior_memory
,
1074 /* Initialize the Win32 backend. */
1076 initialize_low (void)
1078 set_target_ops (&win32_target_ops
);