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)
48 int using_threads
= 1;
51 static HANDLE current_process_handle
= NULL
;
52 static DWORD current_process_id
= 0;
53 static enum target_signal last_sig
= TARGET_SIGNAL_0
;
55 /* The current debug event from WaitForDebugEvent. */
56 static DEBUG_EVENT current_event
;
58 static int debug_registers_changed
= 0;
59 static int debug_registers_used
= 0;
60 static unsigned dr
[8];
62 typedef BOOL
winapi_DebugActiveProcessStop (DWORD dwProcessId
);
63 typedef BOOL
winapi_DebugSetProcessKillOnExit (BOOL KillOnExit
);
65 #define FLAG_TRACE_BIT 0x100
66 #define CONTEXT_DEBUGGER (CONTEXT_FULL | CONTEXT_FLOATING_POINT)
67 #define CONTEXT_DEBUGGER_DR CONTEXT_DEBUGGER | CONTEXT_DEBUG_REGISTERS \
68 | CONTEXT_EXTENDED_REGISTERS
70 /* Thread information structure used to track extra information about
72 typedef struct thread_info_struct
79 static DWORD main_thread_id
= 0;
81 /* Get the thread ID from the current selected inferior (the current
84 current_inferior_tid (void)
86 thread_info
*th
= inferior_target_data (current_inferior
);
90 /* Find a thread record given a thread id. If GET_CONTEXT is set then
91 also retrieve the context for this thread. */
93 thread_rec (DWORD id
, int get_context
)
95 struct thread_info
*thread
;
98 thread
= (struct thread_info
*) find_inferior_id (&all_threads
, id
);
102 th
= inferior_target_data (thread
);
103 if (!th
->suspend_count
&& get_context
)
105 if (get_context
> 0 && id
!= current_event
.dwThreadId
)
106 th
->suspend_count
= SuspendThread (th
->h
) + 1;
107 else if (get_context
< 0)
108 th
->suspend_count
= -1;
110 th
->context
.ContextFlags
= CONTEXT_DEBUGGER_DR
;
112 GetThreadContext (th
->h
, &th
->context
);
114 if (id
== current_event
.dwThreadId
)
116 /* Copy dr values from that thread. */
117 dr
[0] = th
->context
.Dr0
;
118 dr
[1] = th
->context
.Dr1
;
119 dr
[2] = th
->context
.Dr2
;
120 dr
[3] = th
->context
.Dr3
;
121 dr
[6] = th
->context
.Dr6
;
122 dr
[7] = th
->context
.Dr7
;
129 /* Add a thread to the thread list. */
131 child_add_thread (DWORD tid
, HANDLE h
)
135 if ((th
= thread_rec (tid
, FALSE
)))
138 th
= (thread_info
*) malloc (sizeof (*th
));
139 memset (th
, 0, sizeof (*th
));
143 add_thread (tid
, th
, (unsigned int) tid
);
144 set_inferior_regcache_data ((struct thread_info
*)
145 find_inferior_id (&all_threads
, tid
),
146 new_register_cache ());
148 /* Set the debug registers for the new thread if they are used. */
149 if (debug_registers_used
)
151 /* Only change the value of the debug registers. */
152 th
->context
.ContextFlags
= CONTEXT_DEBUGGER_DR
;
154 GetThreadContext (th
->h
, &th
->context
);
156 th
->context
.Dr0
= dr
[0];
157 th
->context
.Dr1
= dr
[1];
158 th
->context
.Dr2
= dr
[2];
159 th
->context
.Dr3
= dr
[3];
160 /* th->context.Dr6 = dr[6];
161 FIXME: should we set dr6 also ?? */
162 th
->context
.Dr7
= dr
[7];
163 SetThreadContext (th
->h
, &th
->context
);
164 th
->context
.ContextFlags
= 0;
170 /* Delete a thread from the list of threads. */
172 delete_thread_info (struct inferior_list_entry
*thread
)
174 thread_info
*th
= inferior_target_data ((struct thread_info
*) thread
);
176 remove_thread ((struct thread_info
*) thread
);
181 /* Delete a thread from the list of threads. */
183 child_delete_thread (DWORD id
)
185 struct inferior_list_entry
*thread
;
187 /* If the last thread is exiting, just return. */
188 if (all_threads
.head
== all_threads
.tail
)
191 thread
= find_inferior_id (&all_threads
, id
);
195 delete_thread_info (thread
);
198 /* Transfer memory from/to the debugged process. */
200 child_xfer_memory (CORE_ADDR memaddr
, char *our
, int len
,
201 int write
, struct target_ops
*target
)
204 long addr
= (long) memaddr
;
208 WriteProcessMemory (current_process_handle
, (LPVOID
) addr
,
209 (LPCVOID
) our
, len
, &done
);
210 FlushInstructionCache (current_process_handle
, (LPCVOID
) addr
, len
);
214 ReadProcessMemory (current_process_handle
, (LPCVOID
) addr
, (LPVOID
) our
,
220 /* Generally, what has the program done? */
223 /* The program has exited. The exit status is in value.integer. */
224 TARGET_WAITKIND_EXITED
,
226 /* The program has stopped with a signal. Which signal is in
228 TARGET_WAITKIND_STOPPED
,
230 /* The program is letting us know that it dynamically loaded something
231 (e.g. it called load(2) on AIX). */
232 TARGET_WAITKIND_LOADED
,
234 /* The program has exec'ed a new executable file. The new file's
235 pathname is pointed to by value.execd_pathname. */
237 TARGET_WAITKIND_EXECD
,
239 /* Nothing happened, but we stopped anyway. This perhaps should be handled
240 within target_wait, but I'm not sure target_wait should be resuming the
242 TARGET_WAITKIND_SPURIOUS
,
245 struct target_waitstatus
247 enum target_waitkind kind
;
249 /* Forked child pid, execd pathname, exit status or signal number. */
253 enum target_signal sig
;
255 char *execd_pathname
;
262 #define FCS_REGNUM 27
263 #define FOP_REGNUM 31
265 #define context_offset(x) ((int)&(((CONTEXT *)NULL)->x))
266 static const int mappings
[] = {
267 context_offset (Eax
),
268 context_offset (Ecx
),
269 context_offset (Edx
),
270 context_offset (Ebx
),
271 context_offset (Esp
),
272 context_offset (Ebp
),
273 context_offset (Esi
),
274 context_offset (Edi
),
275 context_offset (Eip
),
276 context_offset (EFlags
),
277 context_offset (SegCs
),
278 context_offset (SegSs
),
279 context_offset (SegDs
),
280 context_offset (SegEs
),
281 context_offset (SegFs
),
282 context_offset (SegGs
),
283 context_offset (FloatSave
.RegisterArea
[0 * 10]),
284 context_offset (FloatSave
.RegisterArea
[1 * 10]),
285 context_offset (FloatSave
.RegisterArea
[2 * 10]),
286 context_offset (FloatSave
.RegisterArea
[3 * 10]),
287 context_offset (FloatSave
.RegisterArea
[4 * 10]),
288 context_offset (FloatSave
.RegisterArea
[5 * 10]),
289 context_offset (FloatSave
.RegisterArea
[6 * 10]),
290 context_offset (FloatSave
.RegisterArea
[7 * 10]),
291 context_offset (FloatSave
.ControlWord
),
292 context_offset (FloatSave
.StatusWord
),
293 context_offset (FloatSave
.TagWord
),
294 context_offset (FloatSave
.ErrorSelector
),
295 context_offset (FloatSave
.ErrorOffset
),
296 context_offset (FloatSave
.DataSelector
),
297 context_offset (FloatSave
.DataOffset
),
298 context_offset (FloatSave
.ErrorSelector
),
300 context_offset (ExtendedRegisters
[10 * 16]),
301 context_offset (ExtendedRegisters
[11 * 16]),
302 context_offset (ExtendedRegisters
[12 * 16]),
303 context_offset (ExtendedRegisters
[13 * 16]),
304 context_offset (ExtendedRegisters
[14 * 16]),
305 context_offset (ExtendedRegisters
[15 * 16]),
306 context_offset (ExtendedRegisters
[16 * 16]),
307 context_offset (ExtendedRegisters
[17 * 16]),
309 context_offset (ExtendedRegisters
[24])
312 #undef context_offset
314 /* Clear out any old thread list and reintialize it to a pristine
317 child_init_thread_list (void)
319 for_each_inferior (&all_threads
, delete_thread_info
);
323 do_initial_child_stuff (DWORD pid
)
327 last_sig
= TARGET_SIGNAL_0
;
329 debug_registers_changed
= 0;
330 debug_registers_used
= 0;
331 for (i
= 0; i
< sizeof (dr
) / sizeof (dr
[0]); i
++)
333 memset (¤t_event
, 0, sizeof (current_event
));
335 child_init_thread_list ();
338 /* Resume all artificially suspended threads if we are continuing
341 continue_one_thread (struct inferior_list_entry
*this_thread
, void *id_ptr
)
343 struct thread_info
*thread
= (struct thread_info
*) this_thread
;
344 int thread_id
= * (int *) id_ptr
;
345 thread_info
*th
= inferior_target_data (thread
);
348 if ((thread_id
== -1 || thread_id
== th
->tid
)
349 && th
->suspend_count
)
351 for (i
= 0; i
< th
->suspend_count
; i
++)
352 (void) ResumeThread (th
->h
);
353 th
->suspend_count
= 0;
354 if (debug_registers_changed
)
356 /* Only change the value of the debug registers. */
357 th
->context
.ContextFlags
= CONTEXT_DEBUG_REGISTERS
;
358 th
->context
.Dr0
= dr
[0];
359 th
->context
.Dr1
= dr
[1];
360 th
->context
.Dr2
= dr
[2];
361 th
->context
.Dr3
= dr
[3];
362 /* th->context.Dr6 = dr[6];
363 FIXME: should we set dr6 also ?? */
364 th
->context
.Dr7
= dr
[7];
365 SetThreadContext (th
->h
, &th
->context
);
366 th
->context
.ContextFlags
= 0;
374 child_continue (DWORD continue_status
, int thread_id
)
378 res
= ContinueDebugEvent (current_event
.dwProcessId
,
379 current_event
.dwThreadId
, continue_status
);
382 find_inferior (&all_threads
, continue_one_thread
, &thread_id
);
384 debug_registers_changed
= 0;
388 /* Fetch register(s) from gdbserver regcache data. */
390 do_child_fetch_inferior_registers (thread_info
*th
, int r
)
392 char *context_offset
= ((char *) &th
->context
) + mappings
[r
];
396 l
= *((long *) context_offset
) & 0xffff;
397 supply_register (r
, (char *) &l
);
399 else if (r
== FOP_REGNUM
)
401 l
= (*((long *) context_offset
) >> 16) & ((1 << 11) - 1);
402 supply_register (r
, (char *) &l
);
405 supply_register (r
, context_offset
);
408 /* Fetch register(s) from the current thread context. */
410 child_fetch_inferior_registers (int r
)
413 thread_info
*th
= thread_rec (current_inferior_tid (), TRUE
);
414 if (r
== -1 || r
== 0 || r
> NUM_REGS
)
415 child_fetch_inferior_registers (NUM_REGS
);
417 for (regno
= 0; regno
< r
; regno
++)
418 do_child_fetch_inferior_registers (th
, regno
);
421 /* Get register from gdbserver regcache data. */
423 do_child_store_inferior_registers (thread_info
*th
, int r
)
425 collect_register (r
, ((char *) &th
->context
) + mappings
[r
]);
428 /* Store a new register value into the current thread context. We don't
429 change the program's context until later, when we resume it. */
431 child_store_inferior_registers (int r
)
434 thread_info
*th
= thread_rec (current_inferior_tid (), TRUE
);
435 if (r
== -1 || r
== 0 || r
> NUM_REGS
)
436 child_store_inferior_registers (NUM_REGS
);
438 for (regno
= 0; regno
< r
; regno
++)
439 do_child_store_inferior_registers (th
, regno
);
442 /* Start a new process.
443 PROGRAM is a path to the program to execute.
444 ARGS is a standard NULL-terminated array of arguments,
445 to be passed to the inferior as ``argv''.
446 Returns the new PID on success, -1 on failure. Registers the new
447 process with the process list. */
449 win32_create_inferior (char *program
, char **program_args
)
452 char real_path
[MAXPATHLEN
];
453 char *orig_path
, *new_path
, *path_ptr
;
457 PROCESS_INFORMATION pi
;
465 error ("No executable specified, specify executable to debug.\n");
467 memset (&si
, 0, sizeof (si
));
470 flags
= DEBUG_PROCESS
| DEBUG_ONLY_THIS_PROCESS
;
474 path_ptr
= getenv ("PATH");
477 orig_path
= alloca (strlen (path_ptr
) + 1);
478 new_path
= alloca (cygwin_posix_to_win32_path_list_buf_size (path_ptr
));
479 strcpy (orig_path
, path_ptr
);
480 cygwin_posix_to_win32_path_list (path_ptr
, new_path
);
481 setenv ("PATH", new_path
, 1);
483 cygwin_conv_to_win32_path (program
, real_path
);
487 argslen
= strlen (program
) + 1;
488 for (argc
= 1; program_args
[argc
]; argc
++)
489 argslen
+= strlen (program_args
[argc
]) + 1;
490 args
= alloca (argslen
);
491 strcpy (args
, program
);
492 for (argc
= 1; program_args
[argc
]; argc
++)
494 /* FIXME: Can we do better about quoting? How does Cygwin
497 strcat (args
, program_args
[argc
]);
499 OUTMSG2 (("Command line is %s\n", args
));
501 flags
|= CREATE_NEW_PROCESS_GROUP
;
503 ret
= CreateProcess (0, args
, /* command line */
506 TRUE
, /* inherit handles */
507 flags
, /* start flags */
508 winenv
, NULL
, /* current directory */
513 setenv ("PATH", orig_path
, 1);
518 error ("Error creating process %s, (error %d): %s\n", args
,
519 (int) GetLastError (), strerror (GetLastError ()));
523 OUTMSG2 (("Process created: %s\n", (char *) args
));
526 CloseHandle (pi
.hThread
);
528 current_process_handle
= pi
.hProcess
;
529 current_process_id
= pi
.dwProcessId
;
531 do_initial_child_stuff (current_process_id
);
533 return current_process_id
;
536 /* Attach to a running process.
537 PID is the process ID to attach to, specified by the user
538 or a higher layer. */
540 win32_attach (unsigned long pid
)
543 HMODULE kernel32
= LoadLibrary ("KERNEL32.DLL");
544 winapi_DebugActiveProcessStop
*DebugActiveProcessStop
= NULL
;
545 winapi_DebugSetProcessKillOnExit
*DebugSetProcessKillOnExit
= NULL
;
547 DebugActiveProcessStop
=
548 (winapi_DebugActiveProcessStop
*) GetProcAddress (kernel32
,
549 "DebugActiveProcessStop");
550 DebugSetProcessKillOnExit
=
551 (winapi_DebugSetProcessKillOnExit
*) GetProcAddress (kernel32
,
552 "DebugSetProcessKillOnExit");
554 res
= DebugActiveProcess (pid
) ? 1 : 0;
557 error ("Attach to process failed.");
559 if (DebugSetProcessKillOnExit
!= NULL
)
560 DebugSetProcessKillOnExit (FALSE
);
562 current_process_id
= pid
;
563 current_process_handle
= OpenProcess (PROCESS_ALL_ACCESS
, FALSE
, pid
);
565 if (current_process_handle
== NULL
)
568 if (DebugActiveProcessStop
!= NULL
)
569 DebugActiveProcessStop (current_process_id
);
573 do_initial_child_stuff (pid
);
575 FreeLibrary (kernel32
);
580 /* Kill all inferiors. */
584 if (current_process_handle
== NULL
)
587 TerminateProcess (current_process_handle
, 0);
590 if (!child_continue (DBG_CONTINUE
, -1))
592 if (!WaitForDebugEvent (¤t_event
, INFINITE
))
594 if (current_event
.dwDebugEventCode
== EXIT_PROCESS_DEBUG_EVENT
)
599 /* Detach from all inferiors. */
603 HMODULE kernel32
= LoadLibrary ("KERNEL32.DLL");
604 winapi_DebugActiveProcessStop
*DebugActiveProcessStop
= NULL
;
605 winapi_DebugSetProcessKillOnExit
*DebugSetProcessKillOnExit
= NULL
;
607 DebugActiveProcessStop
=
608 (winapi_DebugActiveProcessStop
*) GetProcAddress (kernel32
,
609 "DebugActiveProcessStop");
610 DebugSetProcessKillOnExit
=
611 (winapi_DebugSetProcessKillOnExit
*) GetProcAddress (kernel32
,
612 "DebugSetProcessKillOnExit");
614 if (DebugSetProcessKillOnExit
!= NULL
)
615 DebugSetProcessKillOnExit (FALSE
);
617 if (DebugActiveProcessStop
!= NULL
)
618 DebugActiveProcessStop (current_process_id
);
622 FreeLibrary (kernel32
);
625 /* Return 1 iff the thread with thread ID TID is alive. */
627 win32_thread_alive (unsigned long tid
)
631 /* Our thread list is reliable; don't bother to poll target
633 if (find_inferior_id (&all_threads
, tid
) != NULL
)
640 /* Resume the inferior process. RESUME_INFO describes how we want
643 win32_resume (struct thread_resume
*resume_info
)
646 enum target_signal sig
;
649 DWORD continue_status
= DBG_CONTINUE
;
651 /* This handles the very limited set of resume packets that GDB can
652 currently produce. */
654 if (resume_info
[0].thread
== -1)
656 else if (resume_info
[1].thread
== -1 && !resume_info
[1].leave_stopped
)
659 /* Yes, we're ignoring resume_info[0].thread. It'd be tricky to make
660 the Windows resume code do the right thing for thread switching. */
661 tid
= current_event
.dwThreadId
;
663 if (resume_info
[0].thread
!= -1)
665 sig
= resume_info
[0].sig
;
666 step
= resume_info
[0].step
;
674 if (sig
!= TARGET_SIGNAL_0
)
676 if (current_event
.dwDebugEventCode
!= EXCEPTION_DEBUG_EVENT
)
678 OUTMSG (("Cannot continue with signal %d here.\n", sig
));
680 else if (sig
== last_sig
)
681 continue_status
= DBG_EXCEPTION_NOT_HANDLED
;
683 OUTMSG (("Can only continue with recieved signal %d.\n", last_sig
));
686 last_sig
= TARGET_SIGNAL_0
;
688 /* Get context for the currently selected thread. */
689 th
= thread_rec (current_event
.dwThreadId
, FALSE
);
692 if (th
->context
.ContextFlags
)
694 if (debug_registers_changed
)
696 th
->context
.Dr0
= dr
[0];
697 th
->context
.Dr1
= dr
[1];
698 th
->context
.Dr2
= dr
[2];
699 th
->context
.Dr3
= dr
[3];
700 /* th->context.Dr6 = dr[6];
701 FIXME: should we set dr6 also ?? */
702 th
->context
.Dr7
= dr
[7];
705 /* Move register values from the inferior into the thread
706 context structure. */
707 regcache_invalidate ();
710 th
->context
.EFlags
|= FLAG_TRACE_BIT
;
712 SetThreadContext (th
->h
, &th
->context
);
713 th
->context
.ContextFlags
= 0;
717 /* Allow continuing with the same signal that interrupted us.
718 Otherwise complain. */
720 child_continue (continue_status
, tid
);
724 handle_exception (struct target_waitstatus
*ourstatus
)
727 DWORD code
= current_event
.u
.Exception
.ExceptionRecord
.ExceptionCode
;
729 ourstatus
->kind
= TARGET_WAITKIND_STOPPED
;
731 /* Record the context of the current thread. */
732 th
= thread_rec (current_event
.dwThreadId
, -1);
736 case EXCEPTION_ACCESS_VIOLATION
:
737 OUTMSG2 (("EXCEPTION_ACCESS_VIOLATION"));
738 ourstatus
->value
.sig
= TARGET_SIGNAL_SEGV
;
740 case STATUS_STACK_OVERFLOW
:
741 OUTMSG2 (("STATUS_STACK_OVERFLOW"));
742 ourstatus
->value
.sig
= TARGET_SIGNAL_SEGV
;
744 case STATUS_FLOAT_DENORMAL_OPERAND
:
745 OUTMSG2 (("STATUS_FLOAT_DENORMAL_OPERAND"));
746 ourstatus
->value
.sig
= TARGET_SIGNAL_FPE
;
748 case EXCEPTION_ARRAY_BOUNDS_EXCEEDED
:
749 OUTMSG2 (("EXCEPTION_ARRAY_BOUNDS_EXCEEDED"));
750 ourstatus
->value
.sig
= TARGET_SIGNAL_FPE
;
752 case STATUS_FLOAT_INEXACT_RESULT
:
753 OUTMSG2 (("STATUS_FLOAT_INEXACT_RESULT"));
754 ourstatus
->value
.sig
= TARGET_SIGNAL_FPE
;
756 case STATUS_FLOAT_INVALID_OPERATION
:
757 OUTMSG2 (("STATUS_FLOAT_INVALID_OPERATION"));
758 ourstatus
->value
.sig
= TARGET_SIGNAL_FPE
;
760 case STATUS_FLOAT_OVERFLOW
:
761 OUTMSG2 (("STATUS_FLOAT_OVERFLOW"));
762 ourstatus
->value
.sig
= TARGET_SIGNAL_FPE
;
764 case STATUS_FLOAT_STACK_CHECK
:
765 OUTMSG2 (("STATUS_FLOAT_STACK_CHECK"));
766 ourstatus
->value
.sig
= TARGET_SIGNAL_FPE
;
768 case STATUS_FLOAT_UNDERFLOW
:
769 OUTMSG2 (("STATUS_FLOAT_UNDERFLOW"));
770 ourstatus
->value
.sig
= TARGET_SIGNAL_FPE
;
772 case STATUS_FLOAT_DIVIDE_BY_ZERO
:
773 OUTMSG2 (("STATUS_FLOAT_DIVIDE_BY_ZERO"));
774 ourstatus
->value
.sig
= TARGET_SIGNAL_FPE
;
776 case STATUS_INTEGER_DIVIDE_BY_ZERO
:
777 OUTMSG2 (("STATUS_INTEGER_DIVIDE_BY_ZERO"));
778 ourstatus
->value
.sig
= TARGET_SIGNAL_FPE
;
780 case STATUS_INTEGER_OVERFLOW
:
781 OUTMSG2 (("STATUS_INTEGER_OVERFLOW"));
782 ourstatus
->value
.sig
= TARGET_SIGNAL_FPE
;
784 case EXCEPTION_BREAKPOINT
:
785 OUTMSG2 (("EXCEPTION_BREAKPOINT"));
786 ourstatus
->value
.sig
= TARGET_SIGNAL_TRAP
;
789 OUTMSG2 (("DBG_CONTROL_C"));
790 ourstatus
->value
.sig
= TARGET_SIGNAL_INT
;
792 case DBG_CONTROL_BREAK
:
793 OUTMSG2 (("DBG_CONTROL_BREAK"));
794 ourstatus
->value
.sig
= TARGET_SIGNAL_INT
;
796 case EXCEPTION_SINGLE_STEP
:
797 OUTMSG2 (("EXCEPTION_SINGLE_STEP"));
798 ourstatus
->value
.sig
= TARGET_SIGNAL_TRAP
;
800 case EXCEPTION_ILLEGAL_INSTRUCTION
:
801 OUTMSG2 (("EXCEPTION_ILLEGAL_INSTRUCTION"));
802 ourstatus
->value
.sig
= TARGET_SIGNAL_ILL
;
804 case EXCEPTION_PRIV_INSTRUCTION
:
805 OUTMSG2 (("EXCEPTION_PRIV_INSTRUCTION"));
806 ourstatus
->value
.sig
= TARGET_SIGNAL_ILL
;
808 case EXCEPTION_NONCONTINUABLE_EXCEPTION
:
809 OUTMSG2 (("EXCEPTION_NONCONTINUABLE_EXCEPTION"));
810 ourstatus
->value
.sig
= TARGET_SIGNAL_ILL
;
813 if (current_event
.u
.Exception
.dwFirstChance
)
815 OUTMSG2 (("gdbserver: unknown target exception 0x%08lx at 0x%08lx",
816 current_event
.u
.Exception
.ExceptionRecord
.ExceptionCode
,
817 (DWORD
) current_event
.u
.Exception
.ExceptionRecord
.
819 ourstatus
->value
.sig
= TARGET_SIGNAL_UNKNOWN
;
823 last_sig
= ourstatus
->value
.sig
;
827 /* Get the next event from the child. Return 1 if the event requires
830 get_child_debug_event (struct target_waitstatus
*ourstatus
)
833 DWORD continue_status
, event_code
;
834 thread_info
*th
= NULL
;
835 static thread_info dummy_thread_info
;
840 last_sig
= TARGET_SIGNAL_0
;
841 ourstatus
->kind
= TARGET_WAITKIND_SPURIOUS
;
843 if (!(debug_event
= WaitForDebugEvent (¤t_event
, 1000)))
847 (struct thread_info
*) find_inferior_id (&all_threads
,
848 current_event
.dwThreadId
);
850 continue_status
= DBG_CONTINUE
;
851 event_code
= current_event
.dwDebugEventCode
;
855 case CREATE_THREAD_DEBUG_EVENT
:
856 OUTMSG2 (("gdbserver: kernel event CREATE_THREAD_DEBUG_EVENT "
857 "for pid=%d tid=%x)\n",
858 (unsigned) current_event
.dwProcessId
,
859 (unsigned) current_event
.dwThreadId
));
861 /* Record the existence of this thread. */
862 th
= child_add_thread (current_event
.dwThreadId
,
863 current_event
.u
.CreateThread
.hThread
);
865 retval
= current_event
.dwThreadId
;
868 case EXIT_THREAD_DEBUG_EVENT
:
869 OUTMSG2 (("gdbserver: kernel event EXIT_THREAD_DEBUG_EVENT "
870 "for pid=%d tid=%x\n",
871 (unsigned) current_event
.dwProcessId
,
872 (unsigned) current_event
.dwThreadId
));
873 child_delete_thread (current_event
.dwThreadId
);
874 th
= &dummy_thread_info
;
877 case CREATE_PROCESS_DEBUG_EVENT
:
878 OUTMSG2 (("gdbserver: kernel event CREATE_PROCESS_DEBUG_EVENT "
879 "for pid=%d tid=%x\n",
880 (unsigned) current_event
.dwProcessId
,
881 (unsigned) current_event
.dwThreadId
));
882 CloseHandle (current_event
.u
.CreateProcessInfo
.hFile
);
884 current_process_handle
= current_event
.u
.CreateProcessInfo
.hProcess
;
885 main_thread_id
= current_event
.dwThreadId
;
887 ourstatus
->kind
= TARGET_WAITKIND_EXECD
;
888 ourstatus
->value
.execd_pathname
= "Main executable";
890 /* Add the main thread. */
892 child_add_thread (main_thread_id
,
893 current_event
.u
.CreateProcessInfo
.hThread
);
895 retval
= ourstatus
->value
.related_pid
= current_event
.dwThreadId
;
898 case EXIT_PROCESS_DEBUG_EVENT
:
899 OUTMSG2 (("gdbserver: kernel event EXIT_PROCESS_DEBUG_EVENT "
900 "for pid=%d tid=%x\n",
901 (unsigned) current_event
.dwProcessId
,
902 (unsigned) current_event
.dwThreadId
));
903 ourstatus
->kind
= TARGET_WAITKIND_EXITED
;
904 ourstatus
->value
.integer
= current_event
.u
.ExitProcess
.dwExitCode
;
905 CloseHandle (current_process_handle
);
906 current_process_handle
= NULL
;
907 retval
= main_thread_id
;
910 case LOAD_DLL_DEBUG_EVENT
:
911 OUTMSG2 (("gdbserver: kernel event LOAD_DLL_DEBUG_EVENT "
912 "for pid=%d tid=%x\n",
913 (unsigned) current_event
.dwProcessId
,
914 (unsigned) current_event
.dwThreadId
));
915 CloseHandle (current_event
.u
.LoadDll
.hFile
);
917 ourstatus
->kind
= TARGET_WAITKIND_LOADED
;
918 ourstatus
->value
.integer
= 0;
919 retval
= main_thread_id
;
922 case UNLOAD_DLL_DEBUG_EVENT
:
923 OUTMSG2 (("gdbserver: kernel event UNLOAD_DLL_DEBUG_EVENT "
924 "for pid=%d tid=%x\n",
925 (unsigned) current_event
.dwProcessId
,
926 (unsigned) current_event
.dwThreadId
));
929 case EXCEPTION_DEBUG_EVENT
:
930 OUTMSG2 (("gdbserver: kernel event EXCEPTION_DEBUG_EVENT "
931 "for pid=%d tid=%x\n",
932 (unsigned) current_event
.dwProcessId
,
933 (unsigned) current_event
.dwThreadId
));
934 retval
= handle_exception (ourstatus
);
937 case OUTPUT_DEBUG_STRING_EVENT
:
938 /* A message from the kernel (or Cygwin). */
939 OUTMSG2 (("gdbserver: kernel event OUTPUT_DEBUG_STRING_EVENT "
940 "for pid=%d tid=%x\n",
941 (unsigned) current_event
.dwProcessId
,
942 (unsigned) current_event
.dwThreadId
));
946 OUTMSG2 (("gdbserver: kernel event unknown "
947 "for pid=%d tid=%x code=%ld\n",
948 (unsigned) current_event
.dwProcessId
,
949 (unsigned) current_event
.dwThreadId
,
950 current_event
.dwDebugEventCode
));
955 (struct thread_info
*) find_inferior_id (&all_threads
,
956 current_event
.dwThreadId
);
958 if (!retval
|| (event_code
!= EXCEPTION_DEBUG_EVENT
&& event_code
!= EXIT_PROCESS_DEBUG_EVENT
))
960 child_continue (continue_status
, -1);
965 thread_rec (current_event
.dwThreadId
, TRUE
);
971 /* Wait for the inferior process to change state.
972 STATUS will be filled in with a response code to send to GDB.
973 Returns the signal which caused the process to stop. */
975 win32_wait (char *status
)
977 struct target_waitstatus our_status
;
983 get_child_debug_event (&our_status
);
985 if (our_status
.kind
== TARGET_WAITKIND_EXITED
)
987 OUTMSG2 (("Child exited with retcode = %x\n",
988 our_status
.value
.integer
));
992 child_fetch_inferior_registers (-1);
994 return our_status
.value
.integer
;
996 else if (our_status
.kind
== TARGET_WAITKIND_STOPPED
)
998 OUTMSG2 (("Child Stopped with signal = %x \n",
999 WSTOPSIG (our_status
.value
.sig
)));
1003 child_fetch_inferior_registers (-1);
1005 return our_status
.value
.sig
;
1008 OUTMSG (("Ignoring unknown internal event, %d\n", our_status
.kind
));
1011 struct thread_resume resume
;
1015 resume
.leave_stopped
= 0;
1016 win32_resume (&resume
);
1021 /* Fetch registers from the inferior process.
1022 If REGNO is -1, fetch all registers; otherwise, fetch at least REGNO. */
1024 win32_fetch_inferior_registers (int regno
)
1026 child_fetch_inferior_registers (regno
);
1029 /* Store registers to the inferior process.
1030 If REGNO is -1, store all registers; otherwise, store at least REGNO. */
1032 win32_store_inferior_registers (int regno
)
1034 child_store_inferior_registers (regno
);
1037 /* Read memory from the inferior process. This should generally be
1038 called through read_inferior_memory, which handles breakpoint shadowing.
1039 Read LEN bytes at MEMADDR into a buffer at MYADDR. */
1041 win32_read_inferior_memory (CORE_ADDR memaddr
, unsigned char *myaddr
, int len
)
1043 return child_xfer_memory (memaddr
, myaddr
, len
, 0, 0) != len
;
1046 /* Write memory to the inferior process. This should generally be
1047 called through write_inferior_memory, which handles breakpoint shadowing.
1048 Write LEN bytes from the buffer at MYADDR to MEMADDR.
1049 Returns 0 on success and errno on failure. */
1051 win32_write_inferior_memory (CORE_ADDR memaddr
, const unsigned char *myaddr
,
1054 return child_xfer_memory (memaddr
, (char *) myaddr
, len
, 1, 0) != len
;
1057 static struct target_ops win32_target_ops
= {
1058 win32_create_inferior
,
1065 win32_fetch_inferior_registers
,
1066 win32_store_inferior_registers
,
1067 win32_read_inferior_memory
,
1068 win32_write_inferior_memory
,
1073 /* Initialize the Win32 backend. */
1075 initialize_low (void)
1077 set_target_ops (&win32_target_ops
);