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 TerminateProcess (current_process_handle
, 0);
588 if (!child_continue (DBG_CONTINUE
, -1))
590 if (!WaitForDebugEvent (¤t_event
, INFINITE
))
592 if (current_event
.dwDebugEventCode
== EXIT_PROCESS_DEBUG_EVENT
)
597 /* Detach from all inferiors. */
601 HMODULE kernel32
= LoadLibrary ("KERNEL32.DLL");
602 winapi_DebugActiveProcessStop
*DebugActiveProcessStop
= NULL
;
603 winapi_DebugSetProcessKillOnExit
*DebugSetProcessKillOnExit
= NULL
;
605 DebugActiveProcessStop
=
606 (winapi_DebugActiveProcessStop
*) GetProcAddress (kernel32
,
607 "DebugActiveProcessStop");
608 DebugSetProcessKillOnExit
=
609 (winapi_DebugSetProcessKillOnExit
*) GetProcAddress (kernel32
,
610 "DebugSetProcessKillOnExit");
612 if (DebugSetProcessKillOnExit
!= NULL
)
613 DebugSetProcessKillOnExit (FALSE
);
615 if (DebugActiveProcessStop
!= NULL
)
616 DebugActiveProcessStop (current_process_id
);
620 FreeLibrary (kernel32
);
623 /* Return 1 iff the thread with thread ID TID is alive. */
625 win32_thread_alive (unsigned long tid
)
629 /* Our thread list is reliable; don't bother to poll target
631 if (find_inferior_id (&all_threads
, tid
) != NULL
)
638 /* Resume the inferior process. RESUME_INFO describes how we want
641 win32_resume (struct thread_resume
*resume_info
)
644 enum target_signal sig
;
647 DWORD continue_status
= DBG_CONTINUE
;
649 /* This handles the very limited set of resume packets that GDB can
650 currently produce. */
652 if (resume_info
[0].thread
== -1)
654 else if (resume_info
[1].thread
== -1 && !resume_info
[1].leave_stopped
)
657 /* Yes, we're ignoring resume_info[0].thread. It'd be tricky to make
658 the Windows resume code do the right thing for thread switching. */
659 tid
= current_event
.dwThreadId
;
661 if (resume_info
[0].thread
!= -1)
663 sig
= resume_info
[0].sig
;
664 step
= resume_info
[0].step
;
672 if (sig
!= TARGET_SIGNAL_0
)
674 if (current_event
.dwDebugEventCode
!= EXCEPTION_DEBUG_EVENT
)
676 OUTMSG (("Cannot continue with signal %d here.\n", sig
));
678 else if (sig
== last_sig
)
679 continue_status
= DBG_EXCEPTION_NOT_HANDLED
;
681 OUTMSG (("Can only continue with recieved signal %d.\n", last_sig
));
684 last_sig
= TARGET_SIGNAL_0
;
686 /* Get context for the currently selected thread. */
687 th
= thread_rec (current_event
.dwThreadId
, FALSE
);
690 if (th
->context
.ContextFlags
)
692 if (debug_registers_changed
)
694 th
->context
.Dr0
= dr
[0];
695 th
->context
.Dr1
= dr
[1];
696 th
->context
.Dr2
= dr
[2];
697 th
->context
.Dr3
= dr
[3];
698 /* th->context.Dr6 = dr[6];
699 FIXME: should we set dr6 also ?? */
700 th
->context
.Dr7
= dr
[7];
703 /* Move register values from the inferior into the thread
704 context structure. */
705 regcache_invalidate ();
708 th
->context
.EFlags
|= FLAG_TRACE_BIT
;
710 SetThreadContext (th
->h
, &th
->context
);
711 th
->context
.ContextFlags
= 0;
715 /* Allow continuing with the same signal that interrupted us.
716 Otherwise complain. */
718 child_continue (continue_status
, tid
);
722 handle_exception (struct target_waitstatus
*ourstatus
)
725 DWORD code
= current_event
.u
.Exception
.ExceptionRecord
.ExceptionCode
;
727 ourstatus
->kind
= TARGET_WAITKIND_STOPPED
;
729 /* Record the context of the current thread. */
730 th
= thread_rec (current_event
.dwThreadId
, -1);
734 case EXCEPTION_ACCESS_VIOLATION
:
735 OUTMSG2 (("EXCEPTION_ACCESS_VIOLATION"));
736 ourstatus
->value
.sig
= TARGET_SIGNAL_SEGV
;
738 case STATUS_STACK_OVERFLOW
:
739 OUTMSG2 (("STATUS_STACK_OVERFLOW"));
740 ourstatus
->value
.sig
= TARGET_SIGNAL_SEGV
;
742 case STATUS_FLOAT_DENORMAL_OPERAND
:
743 OUTMSG2 (("STATUS_FLOAT_DENORMAL_OPERAND"));
744 ourstatus
->value
.sig
= TARGET_SIGNAL_FPE
;
746 case EXCEPTION_ARRAY_BOUNDS_EXCEEDED
:
747 OUTMSG2 (("EXCEPTION_ARRAY_BOUNDS_EXCEEDED"));
748 ourstatus
->value
.sig
= TARGET_SIGNAL_FPE
;
750 case STATUS_FLOAT_INEXACT_RESULT
:
751 OUTMSG2 (("STATUS_FLOAT_INEXACT_RESULT"));
752 ourstatus
->value
.sig
= TARGET_SIGNAL_FPE
;
754 case STATUS_FLOAT_INVALID_OPERATION
:
755 OUTMSG2 (("STATUS_FLOAT_INVALID_OPERATION"));
756 ourstatus
->value
.sig
= TARGET_SIGNAL_FPE
;
758 case STATUS_FLOAT_OVERFLOW
:
759 OUTMSG2 (("STATUS_FLOAT_OVERFLOW"));
760 ourstatus
->value
.sig
= TARGET_SIGNAL_FPE
;
762 case STATUS_FLOAT_STACK_CHECK
:
763 OUTMSG2 (("STATUS_FLOAT_STACK_CHECK"));
764 ourstatus
->value
.sig
= TARGET_SIGNAL_FPE
;
766 case STATUS_FLOAT_UNDERFLOW
:
767 OUTMSG2 (("STATUS_FLOAT_UNDERFLOW"));
768 ourstatus
->value
.sig
= TARGET_SIGNAL_FPE
;
770 case STATUS_FLOAT_DIVIDE_BY_ZERO
:
771 OUTMSG2 (("STATUS_FLOAT_DIVIDE_BY_ZERO"));
772 ourstatus
->value
.sig
= TARGET_SIGNAL_FPE
;
774 case STATUS_INTEGER_DIVIDE_BY_ZERO
:
775 OUTMSG2 (("STATUS_INTEGER_DIVIDE_BY_ZERO"));
776 ourstatus
->value
.sig
= TARGET_SIGNAL_FPE
;
778 case STATUS_INTEGER_OVERFLOW
:
779 OUTMSG2 (("STATUS_INTEGER_OVERFLOW"));
780 ourstatus
->value
.sig
= TARGET_SIGNAL_FPE
;
782 case EXCEPTION_BREAKPOINT
:
783 OUTMSG2 (("EXCEPTION_BREAKPOINT"));
784 ourstatus
->value
.sig
= TARGET_SIGNAL_TRAP
;
787 OUTMSG2 (("DBG_CONTROL_C"));
788 ourstatus
->value
.sig
= TARGET_SIGNAL_INT
;
790 case DBG_CONTROL_BREAK
:
791 OUTMSG2 (("DBG_CONTROL_BREAK"));
792 ourstatus
->value
.sig
= TARGET_SIGNAL_INT
;
794 case EXCEPTION_SINGLE_STEP
:
795 OUTMSG2 (("EXCEPTION_SINGLE_STEP"));
796 ourstatus
->value
.sig
= TARGET_SIGNAL_TRAP
;
798 case EXCEPTION_ILLEGAL_INSTRUCTION
:
799 OUTMSG2 (("EXCEPTION_ILLEGAL_INSTRUCTION"));
800 ourstatus
->value
.sig
= TARGET_SIGNAL_ILL
;
802 case EXCEPTION_PRIV_INSTRUCTION
:
803 OUTMSG2 (("EXCEPTION_PRIV_INSTRUCTION"));
804 ourstatus
->value
.sig
= TARGET_SIGNAL_ILL
;
806 case EXCEPTION_NONCONTINUABLE_EXCEPTION
:
807 OUTMSG2 (("EXCEPTION_NONCONTINUABLE_EXCEPTION"));
808 ourstatus
->value
.sig
= TARGET_SIGNAL_ILL
;
811 if (current_event
.u
.Exception
.dwFirstChance
)
813 OUTMSG2 (("gdbserver: unknown target exception 0x%08lx at 0x%08lx",
814 current_event
.u
.Exception
.ExceptionRecord
.ExceptionCode
,
815 (DWORD
) current_event
.u
.Exception
.ExceptionRecord
.
817 ourstatus
->value
.sig
= TARGET_SIGNAL_UNKNOWN
;
821 last_sig
= ourstatus
->value
.sig
;
825 /* Get the next event from the child. Return 1 if the event requires
828 get_child_debug_event (struct target_waitstatus
*ourstatus
)
831 DWORD continue_status
, event_code
;
832 thread_info
*th
= NULL
;
833 static thread_info dummy_thread_info
;
838 last_sig
= TARGET_SIGNAL_0
;
839 ourstatus
->kind
= TARGET_WAITKIND_SPURIOUS
;
841 if (!(debug_event
= WaitForDebugEvent (¤t_event
, 1000)))
845 (struct thread_info
*) find_inferior_id (&all_threads
,
846 current_event
.dwThreadId
);
848 continue_status
= DBG_CONTINUE
;
849 event_code
= current_event
.dwDebugEventCode
;
853 case CREATE_THREAD_DEBUG_EVENT
:
854 OUTMSG2 (("gdbserver: kernel event CREATE_THREAD_DEBUG_EVENT "
855 "for pid=%d tid=%x)\n",
856 (unsigned) current_event
.dwProcessId
,
857 (unsigned) current_event
.dwThreadId
));
859 /* Record the existence of this thread. */
860 th
= child_add_thread (current_event
.dwThreadId
,
861 current_event
.u
.CreateThread
.hThread
);
863 retval
= current_event
.dwThreadId
;
866 case EXIT_THREAD_DEBUG_EVENT
:
867 OUTMSG2 (("gdbserver: kernel event EXIT_THREAD_DEBUG_EVENT "
868 "for pid=%d tid=%x\n",
869 (unsigned) current_event
.dwProcessId
,
870 (unsigned) current_event
.dwThreadId
));
871 child_delete_thread (current_event
.dwThreadId
);
872 th
= &dummy_thread_info
;
875 case CREATE_PROCESS_DEBUG_EVENT
:
876 OUTMSG2 (("gdbserver: kernel event CREATE_PROCESS_DEBUG_EVENT "
877 "for pid=%d tid=%x\n",
878 (unsigned) current_event
.dwProcessId
,
879 (unsigned) current_event
.dwThreadId
));
880 CloseHandle (current_event
.u
.CreateProcessInfo
.hFile
);
882 current_process_handle
= current_event
.u
.CreateProcessInfo
.hProcess
;
883 main_thread_id
= current_event
.dwThreadId
;
885 ourstatus
->kind
= TARGET_WAITKIND_EXECD
;
886 ourstatus
->value
.execd_pathname
= "Main executable";
888 /* Add the main thread. */
890 child_add_thread (main_thread_id
,
891 current_event
.u
.CreateProcessInfo
.hThread
);
893 retval
= ourstatus
->value
.related_pid
= current_event
.dwThreadId
;
896 case EXIT_PROCESS_DEBUG_EVENT
:
897 OUTMSG2 (("gdbserver: kernel event EXIT_PROCESS_DEBUG_EVENT "
898 "for pid=%d tid=%x\n",
899 (unsigned) current_event
.dwProcessId
,
900 (unsigned) current_event
.dwThreadId
));
901 ourstatus
->kind
= TARGET_WAITKIND_EXITED
;
902 ourstatus
->value
.integer
= current_event
.u
.ExitProcess
.dwExitCode
;
903 CloseHandle (current_process_handle
);
904 retval
= main_thread_id
;
907 case LOAD_DLL_DEBUG_EVENT
:
908 OUTMSG2 (("gdbserver: kernel event LOAD_DLL_DEBUG_EVENT "
909 "for pid=%d tid=%x\n",
910 (unsigned) current_event
.dwProcessId
,
911 (unsigned) current_event
.dwThreadId
));
912 CloseHandle (current_event
.u
.LoadDll
.hFile
);
914 ourstatus
->kind
= TARGET_WAITKIND_LOADED
;
915 ourstatus
->value
.integer
= 0;
916 retval
= main_thread_id
;
919 case UNLOAD_DLL_DEBUG_EVENT
:
920 OUTMSG2 (("gdbserver: kernel event UNLOAD_DLL_DEBUG_EVENT "
921 "for pid=%d tid=%x\n",
922 (unsigned) current_event
.dwProcessId
,
923 (unsigned) current_event
.dwThreadId
));
926 case EXCEPTION_DEBUG_EVENT
:
927 OUTMSG2 (("gdbserver: kernel event EXCEPTION_DEBUG_EVENT "
928 "for pid=%d tid=%x\n",
929 (unsigned) current_event
.dwProcessId
,
930 (unsigned) current_event
.dwThreadId
));
931 retval
= handle_exception (ourstatus
);
934 case OUTPUT_DEBUG_STRING_EVENT
:
935 /* A message from the kernel (or Cygwin). */
936 OUTMSG2 (("gdbserver: kernel event OUTPUT_DEBUG_STRING_EVENT "
937 "for pid=%d tid=%x\n",
938 (unsigned) current_event
.dwProcessId
,
939 (unsigned) current_event
.dwThreadId
));
943 OUTMSG2 (("gdbserver: kernel event unknown "
944 "for pid=%d tid=%x code=%ld\n",
945 (unsigned) current_event
.dwProcessId
,
946 (unsigned) current_event
.dwThreadId
,
947 current_event
.dwDebugEventCode
));
952 (struct thread_info
*) find_inferior_id (&all_threads
,
953 current_event
.dwThreadId
);
955 if (!retval
|| (event_code
!= EXCEPTION_DEBUG_EVENT
&& event_code
!= EXIT_PROCESS_DEBUG_EVENT
))
957 child_continue (continue_status
, -1);
962 thread_rec (current_event
.dwThreadId
, TRUE
);
968 /* Wait for the inferior process to change state.
969 STATUS will be filled in with a response code to send to GDB.
970 Returns the signal which caused the process to stop. */
972 win32_wait (char *status
)
974 struct target_waitstatus our_status
;
980 get_child_debug_event (&our_status
);
982 if (our_status
.kind
== TARGET_WAITKIND_EXITED
)
984 OUTMSG2 (("Child exited with retcode = %x\n",
985 our_status
.value
.integer
));
989 child_fetch_inferior_registers (-1);
991 return our_status
.value
.integer
;
993 else if (our_status
.kind
== TARGET_WAITKIND_STOPPED
)
995 OUTMSG2 (("Child Stopped with signal = %x \n",
996 WSTOPSIG (our_status
.value
.sig
)));
1000 child_fetch_inferior_registers (-1);
1002 return our_status
.value
.sig
;
1005 OUTMSG (("Ignoring unknown internal event, %d\n", our_status
.kind
));
1008 struct thread_resume resume
;
1012 resume
.leave_stopped
= 0;
1013 win32_resume (&resume
);
1018 /* Fetch registers from the inferior process.
1019 If REGNO is -1, fetch all registers; otherwise, fetch at least REGNO. */
1021 win32_fetch_inferior_registers (int regno
)
1023 child_fetch_inferior_registers (regno
);
1026 /* Store registers to the inferior process.
1027 If REGNO is -1, store all registers; otherwise, store at least REGNO. */
1029 win32_store_inferior_registers (int regno
)
1031 child_store_inferior_registers (regno
);
1034 /* Read memory from the inferior process. This should generally be
1035 called through read_inferior_memory, which handles breakpoint shadowing.
1036 Read LEN bytes at MEMADDR into a buffer at MYADDR. */
1038 win32_read_inferior_memory (CORE_ADDR memaddr
, unsigned char *myaddr
, int len
)
1040 return child_xfer_memory (memaddr
, myaddr
, len
, 0, 0) != len
;
1043 /* Write memory to the inferior process. This should generally be
1044 called through write_inferior_memory, which handles breakpoint shadowing.
1045 Write LEN bytes from the buffer at MYADDR to MEMADDR.
1046 Returns 0 on success and errno on failure. */
1048 win32_write_inferior_memory (CORE_ADDR memaddr
, const unsigned char *myaddr
,
1051 return child_xfer_memory (memaddr
, (char *) myaddr
, len
, 1, 0) != len
;
1054 static struct target_ops win32_target_ops
= {
1055 win32_create_inferior
,
1062 win32_fetch_inferior_registers
,
1063 win32_store_inferior_registers
,
1064 win32_read_inferior_memory
,
1065 win32_write_inferior_memory
,
1070 /* Initialize the Win32 backend. */
1072 initialize_low (void)
1074 set_target_ops (&win32_target_ops
);