X-Git-Url: http://drtracing.org/?a=blobdiff_plain;ds=sidebyside;f=gdb%2Fgdbserver%2Fwin32-low.c;h=e60be5a6df1570f825002f32777fa1bff6daa779;hb=618f726fcb851883a0094aa7fa17003889b7189f;hp=ea83a5eac0749c39d544ac8904508f071d01a070;hpb=41093d818468d60d4ee2dec16fb62e54674c3011;p=deliverable%2Fbinutils-gdb.git
diff --git a/gdb/gdbserver/win32-low.c b/gdb/gdbserver/win32-low.c
index ea83a5eac0..e60be5a6df 100644
--- a/gdb/gdbserver/win32-low.c
+++ b/gdb/gdbserver/win32-low.c
@@ -1,5 +1,5 @@
/* Low level interface to Windows debugging, for gdbserver.
- Copyright (C) 2006, 2007 Free Software Foundation, Inc.
+ Copyright (C) 2006-2016 Free Software Foundation, Inc.
Contributed by Leo Zayas. Based on "win32-nat.c" from GDB.
@@ -7,7 +7,7 @@
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
+ the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
@@ -16,322 +16,414 @@
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor,
- Boston, MA 02110-1301, USA. */
+ along with this program. If not, see . */
#include "server.h"
#include "regcache.h"
-#include "gdb/signals.h"
-
+#include "gdb/fileio.h"
+#include "mem-break.h"
+#include "win32-low.h"
+#include "gdbthread.h"
+#include "dll.h"
+#include "hostio.h"
#include
+#include
#include
+#include
#include
-#include
-#include
#include
#ifndef USE_WIN32API
#include
#endif
-#define LOG 0
+#define OUTMSG(X) do { printf X; fflush (stderr); } while (0)
+
+#define OUTMSG2(X) \
+ do \
+ { \
+ if (debug_threads) \
+ { \
+ printf X; \
+ fflush (stderr); \
+ } \
+ } while (0)
+
+#ifndef _T
+#define _T(x) TEXT (x)
+#endif
-#define OUTMSG(X) do { printf X; fflush (stdout); } while (0)
-#if LOG
-#define OUTMSG2(X) do { printf X; fflush (stdout); } while (0)
+#ifndef COUNTOF
+#define COUNTOF(STR) (sizeof (STR) / sizeof ((STR)[0]))
+#endif
+
+#ifdef _WIN32_WCE
+# define GETPROCADDRESS(DLL, PROC) \
+ ((winapi_ ## PROC) GetProcAddress (DLL, TEXT (#PROC)))
#else
-#define OUTMSG2(X)
+# define GETPROCADDRESS(DLL, PROC) \
+ ((winapi_ ## PROC) GetProcAddress (DLL, #PROC))
#endif
int using_threads = 1;
/* Globals. */
+static int attaching = 0;
static HANDLE current_process_handle = NULL;
static DWORD current_process_id = 0;
-static enum target_signal last_sig = TARGET_SIGNAL_0;
+static DWORD main_thread_id = 0;
+static enum gdb_signal last_sig = GDB_SIGNAL_0;
/* The current debug event from WaitForDebugEvent. */
static DEBUG_EVENT current_event;
-static int debug_registers_changed = 0;
-static int debug_registers_used = 0;
-static unsigned dr[8];
+/* A status that hasn't been reported to the core yet, and so
+ win32_wait should return it next, instead of fetching the next
+ debug event off the win32 API. */
+static struct target_waitstatus cached_status;
-typedef BOOL winapi_DebugActiveProcessStop (DWORD dwProcessId);
-typedef BOOL winapi_DebugSetProcessKillOnExit (BOOL KillOnExit);
+/* Non zero if an interrupt request is to be satisfied by suspending
+ all threads. */
+static int soft_interrupt_requested = 0;
-#define FLAG_TRACE_BIT 0x100
-#define CONTEXT_DEBUGGER (CONTEXT_FULL | CONTEXT_FLOATING_POINT)
-#define CONTEXT_DEBUGGER_DR CONTEXT_DEBUGGER | CONTEXT_DEBUG_REGISTERS \
- | CONTEXT_EXTENDED_REGISTERS
+/* Non zero if the inferior is stopped in a simulated breakpoint done
+ by suspending all the threads. */
+static int faked_breakpoint = 0;
-/* Thread information structure used to track extra information about
- each thread. */
-typedef struct win32_thread_info
-{
- DWORD tid;
- HANDLE h;
- int suspend_count;
- CONTEXT context;
-} win32_thread_info;
-static DWORD main_thread_id = 0;
+const struct target_desc *win32_tdesc;
+
+#define NUM_REGS (the_low_target.num_regs)
+
+typedef BOOL (WINAPI *winapi_DebugActiveProcessStop) (DWORD dwProcessId);
+typedef BOOL (WINAPI *winapi_DebugSetProcessKillOnExit) (BOOL KillOnExit);
+typedef BOOL (WINAPI *winapi_DebugBreakProcess) (HANDLE);
+typedef BOOL (WINAPI *winapi_GenerateConsoleCtrlEvent) (DWORD, DWORD);
+
+static ptid_t win32_wait (ptid_t ptid, struct target_waitstatus *ourstatus,
+ int options);
+static void win32_resume (struct thread_resume *resume_info, size_t n);
+#ifndef _WIN32_WCE
+static void win32_add_all_dlls (void);
+#endif
/* Get the thread ID from the current selected inferior (the current
thread). */
-static DWORD
-current_inferior_tid (void)
+static ptid_t
+current_thread_ptid (void)
{
- win32_thread_info *th = inferior_target_data (current_inferior);
- return th->tid;
+ return current_ptid;
}
-/* Find a thread record given a thread id. If GET_CONTEXT is set then
- also retrieve the context for this thread. */
-static win32_thread_info *
-thread_rec (DWORD id, int get_context)
+/* The current debug event from WaitForDebugEvent. */
+static ptid_t
+debug_event_ptid (DEBUG_EVENT *event)
{
- struct thread_info *thread;
- win32_thread_info *th;
+ return ptid_build (event->dwProcessId, event->dwThreadId, 0);
+}
- thread = (struct thread_info *) find_inferior_id (&all_threads, id);
- if (thread == NULL)
- return NULL;
+/* Get the thread context of the thread associated with TH. */
- th = inferior_target_data (thread);
- if (!th->suspend_count && get_context)
- {
- if (get_context > 0 && id != current_event.dwThreadId)
- th->suspend_count = SuspendThread (th->h) + 1;
- else if (get_context < 0)
- th->suspend_count = -1;
+static void
+win32_get_thread_context (win32_thread_info *th)
+{
+ memset (&th->context, 0, sizeof (CONTEXT));
+ (*the_low_target.get_thread_context) (th);
+#ifdef _WIN32_WCE
+ memcpy (&th->base_context, &th->context, sizeof (CONTEXT));
+#endif
+}
+
+/* Set the thread context of the thread associated with TH. */
+
+static void
+win32_set_thread_context (win32_thread_info *th)
+{
+#ifdef _WIN32_WCE
+ /* Calling SuspendThread on a thread that is running kernel code
+ will report that the suspending was successful, but in fact, that
+ will often not be true. In those cases, the context returned by
+ GetThreadContext will not be correct by the time the thread
+ stops, hence we can't set that context back into the thread when
+ resuming - it will most likelly crash the inferior.
+ Unfortunately, there is no way to know when the thread will
+ really stop. To work around it, we'll only write the context
+ back to the thread when either the user or GDB explicitly change
+ it between stopping and resuming. */
+ if (memcmp (&th->context, &th->base_context, sizeof (CONTEXT)) != 0)
+#endif
+ SetThreadContext (th->h, &th->context);
+}
- th->context.ContextFlags = CONTEXT_DEBUGGER_DR;
+/* Set the thread context of the thread associated with TH. */
- GetThreadContext (th->h, &th->context);
+static void
+win32_prepare_to_resume (win32_thread_info *th)
+{
+ if (the_low_target.prepare_to_resume != NULL)
+ (*the_low_target.prepare_to_resume) (th);
+}
+
+/* See win32-low.h. */
- if (id == current_event.dwThreadId)
+void
+win32_require_context (win32_thread_info *th)
+{
+ if (th->context.ContextFlags == 0)
+ {
+ if (!th->suspended)
{
- /* Copy dr values from that thread. */
- dr[0] = th->context.Dr0;
- dr[1] = th->context.Dr1;
- dr[2] = th->context.Dr2;
- dr[3] = th->context.Dr3;
- dr[6] = th->context.Dr6;
- dr[7] = th->context.Dr7;
+ if (SuspendThread (th->h) == (DWORD) -1)
+ {
+ DWORD err = GetLastError ();
+ OUTMSG (("warning: SuspendThread failed in thread_rec, "
+ "(error %d): %s\n", (int) err, strwinerror (err)));
+ }
+ else
+ th->suspended = 1;
}
+
+ win32_get_thread_context (th);
}
+}
+
+/* Find a thread record given a thread id. If GET_CONTEXT is set then
+ also retrieve the context for this thread. */
+static win32_thread_info *
+thread_rec (ptid_t ptid, int get_context)
+{
+ struct thread_info *thread;
+ win32_thread_info *th;
+
+ thread = (struct thread_info *) find_inferior_id (&all_threads, ptid);
+ if (thread == NULL)
+ return NULL;
+ th = (win32_thread_info *) inferior_target_data (thread);
+ if (get_context)
+ win32_require_context (th);
return th;
}
/* Add a thread to the thread list. */
static win32_thread_info *
-child_add_thread (DWORD tid, HANDLE h)
+child_add_thread (DWORD pid, DWORD tid, HANDLE h, void *tlb)
{
win32_thread_info *th;
+ ptid_t ptid = ptid_build (pid, tid, 0);
- if ((th = thread_rec (tid, FALSE)))
+ if ((th = thread_rec (ptid, FALSE)))
return th;
- th = (win32_thread_info *) malloc (sizeof (*th));
- memset (th, 0, sizeof (*th));
+ th = XCNEW (win32_thread_info);
th->tid = tid;
th->h = h;
+ th->thread_local_base = (CORE_ADDR) (uintptr_t) tlb;
- add_thread (tid, th, (unsigned int) tid);
- set_inferior_regcache_data ((struct thread_info *)
- find_inferior_id (&all_threads, tid),
- new_register_cache ());
+ add_thread (ptid, th);
- /* Set the debug registers for the new thread if they are used. */
- if (debug_registers_used)
- {
- /* Only change the value of the debug registers. */
- th->context.ContextFlags = CONTEXT_DEBUGGER_DR;
-
- GetThreadContext (th->h, &th->context);
-
- th->context.Dr0 = dr[0];
- th->context.Dr1 = dr[1];
- th->context.Dr2 = dr[2];
- th->context.Dr3 = dr[3];
- /* th->context.Dr6 = dr[6];
- FIXME: should we set dr6 also ?? */
- th->context.Dr7 = dr[7];
- SetThreadContext (th->h, &th->context);
- th->context.ContextFlags = 0;
- }
+ if (the_low_target.thread_added != NULL)
+ (*the_low_target.thread_added) (th);
return th;
}
/* Delete a thread from the list of threads. */
static void
-delete_thread_info (struct inferior_list_entry *thread)
+delete_thread_info (struct inferior_list_entry *entry)
{
- win32_thread_info *th = inferior_target_data ((struct thread_info *) thread);
+ struct thread_info *thread = (struct thread_info *) entry;
+ win32_thread_info *th = (win32_thread_info *) inferior_target_data (thread);
- remove_thread ((struct thread_info *) thread);
+ remove_thread (thread);
CloseHandle (th->h);
free (th);
}
/* Delete a thread from the list of threads. */
static void
-child_delete_thread (DWORD id)
+child_delete_thread (DWORD pid, DWORD tid)
{
struct inferior_list_entry *thread;
+ ptid_t ptid;
/* If the last thread is exiting, just return. */
- if (all_threads.head == all_threads.tail)
+ if (one_inferior_p (&all_threads))
return;
- thread = find_inferior_id (&all_threads, id);
+ ptid = ptid_build (pid, tid, 0);
+ thread = find_inferior_id (&all_threads, ptid);
if (thread == NULL)
return;
delete_thread_info (thread);
}
+/* These watchpoint related wrapper functions simply pass on the function call
+ if the low target has registered a corresponding function. */
+
+static int
+win32_supports_z_point_type (char z_type)
+{
+ return (the_low_target.supports_z_point_type != NULL
+ && the_low_target.supports_z_point_type (z_type));
+}
+
+static int
+win32_insert_point (enum raw_bkpt_type type, CORE_ADDR addr,
+ int size, struct raw_breakpoint *bp)
+{
+ if (the_low_target.insert_point != NULL)
+ return the_low_target.insert_point (type, addr, size, bp);
+ else
+ /* Unsupported (see target.h). */
+ return 1;
+}
+
+static int
+win32_remove_point (enum raw_bkpt_type type, CORE_ADDR addr,
+ int size, struct raw_breakpoint *bp)
+{
+ if (the_low_target.remove_point != NULL)
+ return the_low_target.remove_point (type, addr, size, bp);
+ else
+ /* Unsupported (see target.h). */
+ return 1;
+}
+
+static int
+win32_stopped_by_watchpoint (void)
+{
+ if (the_low_target.stopped_by_watchpoint != NULL)
+ return the_low_target.stopped_by_watchpoint ();
+ else
+ return 0;
+}
+
+static CORE_ADDR
+win32_stopped_data_address (void)
+{
+ if (the_low_target.stopped_data_address != NULL)
+ return the_low_target.stopped_data_address ();
+ else
+ return 0;
+}
+
+
/* Transfer memory from/to the debugged process. */
static int
child_xfer_memory (CORE_ADDR memaddr, char *our, int len,
int write, struct target_ops *target)
{
- SIZE_T done;
- long addr = (long) memaddr;
+ BOOL success;
+ SIZE_T done = 0;
+ DWORD lasterror = 0;
+ uintptr_t addr = (uintptr_t) memaddr;
if (write)
{
- WriteProcessMemory (current_process_handle, (LPVOID) addr,
- (LPCVOID) our, len, &done);
+ success = WriteProcessMemory (current_process_handle, (LPVOID) addr,
+ (LPCVOID) our, len, &done);
+ if (!success)
+ lasterror = GetLastError ();
FlushInstructionCache (current_process_handle, (LPCVOID) addr, len);
}
else
{
- ReadProcessMemory (current_process_handle, (LPCVOID) addr, (LPVOID) our,
- len, &done);
+ success = ReadProcessMemory (current_process_handle, (LPCVOID) addr,
+ (LPVOID) our, len, &done);
+ if (!success)
+ lasterror = GetLastError ();
}
- return done;
+ if (!success && lasterror == ERROR_PARTIAL_COPY && done > 0)
+ return done;
+ else
+ return success ? done : -1;
}
-/* Generally, what has the program done? */
-enum target_waitkind
+/* Clear out any old thread list and reinitialize it to a pristine
+ state. */
+static void
+child_init_thread_list (void)
{
- /* The program has exited. The exit status is in value.integer. */
- TARGET_WAITKIND_EXITED,
+ for_each_inferior (&all_threads, delete_thread_info);
+}
- /* The program has stopped with a signal. Which signal is in
- value.sig. */
- TARGET_WAITKIND_STOPPED,
+/* Zero during the child initialization phase, and nonzero otherwise. */
- /* The program is letting us know that it dynamically loaded something
- (e.g. it called load(2) on AIX). */
- TARGET_WAITKIND_LOADED,
+static int child_initialization_done = 0;
- /* The program has exec'ed a new executable file. The new file's
- pathname is pointed to by value.execd_pathname. */
+static void
+do_initial_child_stuff (HANDLE proch, DWORD pid, int attached)
+{
+ struct process_info *proc;
- TARGET_WAITKIND_EXECD,
+ last_sig = GDB_SIGNAL_0;
- /* Nothing happened, but we stopped anyway. This perhaps should be handled
- within target_wait, but I'm not sure target_wait should be resuming the
- inferior. */
- TARGET_WAITKIND_SPURIOUS,
-};
+ current_process_handle = proch;
+ current_process_id = pid;
+ main_thread_id = 0;
-struct target_waitstatus
-{
- enum target_waitkind kind;
+ soft_interrupt_requested = 0;
+ faked_breakpoint = 0;
- /* Forked child pid, execd pathname, exit status or signal number. */
- union
- {
- int integer;
- enum target_signal sig;
- int related_pid;
- char *execd_pathname;
- int syscall_id;
- }
- value;
-};
+ memset (¤t_event, 0, sizeof (current_event));
-#define NUM_REGS 41
-#define FCS_REGNUM 27
-#define FOP_REGNUM 31
-
-#define context_offset(x) ((int)&(((CONTEXT *)NULL)->x))
-static const int mappings[] = {
- context_offset (Eax),
- context_offset (Ecx),
- context_offset (Edx),
- context_offset (Ebx),
- context_offset (Esp),
- context_offset (Ebp),
- context_offset (Esi),
- context_offset (Edi),
- context_offset (Eip),
- context_offset (EFlags),
- context_offset (SegCs),
- context_offset (SegSs),
- context_offset (SegDs),
- context_offset (SegEs),
- context_offset (SegFs),
- context_offset (SegGs),
- context_offset (FloatSave.RegisterArea[0 * 10]),
- context_offset (FloatSave.RegisterArea[1 * 10]),
- context_offset (FloatSave.RegisterArea[2 * 10]),
- context_offset (FloatSave.RegisterArea[3 * 10]),
- context_offset (FloatSave.RegisterArea[4 * 10]),
- context_offset (FloatSave.RegisterArea[5 * 10]),
- context_offset (FloatSave.RegisterArea[6 * 10]),
- context_offset (FloatSave.RegisterArea[7 * 10]),
- context_offset (FloatSave.ControlWord),
- context_offset (FloatSave.StatusWord),
- context_offset (FloatSave.TagWord),
- context_offset (FloatSave.ErrorSelector),
- context_offset (FloatSave.ErrorOffset),
- context_offset (FloatSave.DataSelector),
- context_offset (FloatSave.DataOffset),
- context_offset (FloatSave.ErrorSelector),
- /* XMM0-7 */
- context_offset (ExtendedRegisters[10 * 16]),
- context_offset (ExtendedRegisters[11 * 16]),
- context_offset (ExtendedRegisters[12 * 16]),
- context_offset (ExtendedRegisters[13 * 16]),
- context_offset (ExtendedRegisters[14 * 16]),
- context_offset (ExtendedRegisters[15 * 16]),
- context_offset (ExtendedRegisters[16 * 16]),
- context_offset (ExtendedRegisters[17 * 16]),
- /* MXCSR */
- context_offset (ExtendedRegisters[24])
-};
+ proc = add_process (pid, attached);
+ proc->tdesc = win32_tdesc;
+ child_init_thread_list ();
+ child_initialization_done = 0;
-#undef context_offset
+ if (the_low_target.initial_stuff != NULL)
+ (*the_low_target.initial_stuff) ();
-/* Clear out any old thread list and reintialize it to a pristine
- state. */
-static void
-child_init_thread_list (void)
-{
- for_each_inferior (&all_threads, delete_thread_info);
-}
+ cached_status.kind = TARGET_WAITKIND_IGNORE;
-static void
-do_initial_child_stuff (DWORD pid)
-{
- int i;
+ /* Flush all currently pending debug events (thread and dll list) up
+ to the initial breakpoint. */
+ while (1)
+ {
+ struct target_waitstatus status;
- last_sig = TARGET_SIGNAL_0;
+ win32_wait (minus_one_ptid, &status, 0);
- debug_registers_changed = 0;
- debug_registers_used = 0;
- for (i = 0; i < sizeof (dr) / sizeof (dr[0]); i++)
- dr[i] = 0;
- memset (¤t_event, 0, sizeof (current_event));
+ /* Note win32_wait doesn't return thread events. */
+ if (status.kind != TARGET_WAITKIND_LOADED)
+ {
+ cached_status = status;
+ break;
+ }
- child_init_thread_list ();
+ {
+ struct thread_resume resume;
+
+ resume.thread = minus_one_ptid;
+ resume.kind = resume_continue;
+ resume.sig = 0;
+
+ win32_resume (&resume, 1);
+ }
+ }
+
+#ifndef _WIN32_WCE
+ /* Now that the inferior has been started and all DLLs have been mapped,
+ we can iterate over all DLLs and load them in.
+
+ We avoid doing it any earlier because, on certain versions of Windows,
+ LOAD_DLL_DEBUG_EVENTs are sometimes not complete. In particular,
+ we have seen on Windows 8.1 that the ntdll.dll load event does not
+ include the DLL name, preventing us from creating an associated SO.
+ A possible explanation is that ntdll.dll might be mapped before
+ the SO info gets created by the Windows system -- ntdll.dll is
+ the first DLL to be reported via LOAD_DLL_DEBUG_EVENT and other DLLs
+ do not seem to suffer from that problem.
+
+ Rather than try to work around this sort of issue, it is much
+ simpler to just ignore DLL load/unload events during the startup
+ phase, and then process them all in one batch now. */
+ win32_add_all_dlls ();
+#endif
+
+ child_initialization_done = 1;
}
/* Resume all artificially suspended threads if we are continuing
@@ -341,28 +433,27 @@ continue_one_thread (struct inferior_list_entry *this_thread, void *id_ptr)
{
struct thread_info *thread = (struct thread_info *) this_thread;
int thread_id = * (int *) id_ptr;
- win32_thread_info *th = inferior_target_data (thread);
- int i;
+ win32_thread_info *th = (win32_thread_info *) inferior_target_data (thread);
- if ((thread_id == -1 || thread_id == th->tid)
- && th->suspend_count)
+ if (thread_id == -1 || thread_id == th->tid)
{
- for (i = 0; i < th->suspend_count; i++)
- (void) ResumeThread (th->h);
- th->suspend_count = 0;
- if (debug_registers_changed)
+ win32_prepare_to_resume (th);
+
+ if (th->suspended)
{
- /* Only change the value of the debug registers. */
- th->context.ContextFlags = CONTEXT_DEBUG_REGISTERS;
- th->context.Dr0 = dr[0];
- th->context.Dr1 = dr[1];
- th->context.Dr2 = dr[2];
- th->context.Dr3 = dr[3];
- /* th->context.Dr6 = dr[6];
- FIXME: should we set dr6 also ?? */
- th->context.Dr7 = dr[7];
- SetThreadContext (th->h, &th->context);
- th->context.ContextFlags = 0;
+ if (th->context.ContextFlags)
+ {
+ win32_set_thread_context (th);
+ th->context.ContextFlags = 0;
+ }
+
+ if (ResumeThread (th->h) == (DWORD) -1)
+ {
+ DWORD err = GetLastError ();
+ OUTMSG (("warning: ResumeThread failed in continue_one_thread, "
+ "(error %d): %s\n", (int) err, strwinerror (err)));
+ }
+ th->suspended = 0;
}
}
@@ -372,70 +463,148 @@ continue_one_thread (struct inferior_list_entry *this_thread, void *id_ptr)
static BOOL
child_continue (DWORD continue_status, int thread_id)
{
- BOOL res;
+ /* The inferior will only continue after the ContinueDebugEvent
+ call. */
+ find_inferior (&all_threads, continue_one_thread, &thread_id);
+ faked_breakpoint = 0;
- res = ContinueDebugEvent (current_event.dwProcessId,
- current_event.dwThreadId, continue_status);
- continue_status = 0;
- if (res)
- find_inferior (&all_threads, continue_one_thread, &thread_id);
+ if (!ContinueDebugEvent (current_event.dwProcessId,
+ current_event.dwThreadId,
+ continue_status))
+ return FALSE;
- debug_registers_changed = 0;
- return res;
+ return TRUE;
}
-/* Fetch register(s) from gdbserver regcache data. */
+/* Fetch register(s) from the current thread context. */
static void
-do_child_fetch_inferior_registers (win32_thread_info *th, int r)
+child_fetch_inferior_registers (struct regcache *regcache, int r)
{
- char *context_offset = ((char *) &th->context) + mappings[r];
- long l;
- if (r == FCS_REGNUM)
- {
- l = *((long *) context_offset) & 0xffff;
- supply_register (r, (char *) &l);
- }
- else if (r == FOP_REGNUM)
- {
- l = (*((long *) context_offset) >> 16) & ((1 << 11) - 1);
- supply_register (r, (char *) &l);
- }
+ int regno;
+ win32_thread_info *th = thread_rec (current_thread_ptid (), TRUE);
+ if (r == -1 || r > NUM_REGS)
+ child_fetch_inferior_registers (regcache, NUM_REGS);
else
- supply_register (r, context_offset);
+ for (regno = 0; regno < r; regno++)
+ (*the_low_target.fetch_inferior_register) (regcache, th, regno);
}
-/* Fetch register(s) from the current thread context. */
+/* Store a new register value into the current thread context. We don't
+ change the program's context until later, when we resume it. */
static void
-child_fetch_inferior_registers (int r)
+child_store_inferior_registers (struct regcache *regcache, int r)
{
int regno;
- win32_thread_info *th = thread_rec (current_inferior_tid (), TRUE);
+ win32_thread_info *th = thread_rec (current_thread_ptid (), TRUE);
if (r == -1 || r == 0 || r > NUM_REGS)
- child_fetch_inferior_registers (NUM_REGS);
+ child_store_inferior_registers (regcache, NUM_REGS);
else
for (regno = 0; regno < r; regno++)
- do_child_fetch_inferior_registers (th, regno);
+ (*the_low_target.store_inferior_register) (regcache, th, regno);
}
-/* Get register from gdbserver regcache data. */
-static void
-do_child_store_inferior_registers (win32_thread_info *th, int r)
+/* Map the Windows error number in ERROR to a locale-dependent error
+ message string and return a pointer to it. Typically, the values
+ for ERROR come from GetLastError.
+
+ The string pointed to shall not be modified by the application,
+ but may be overwritten by a subsequent call to strwinerror
+
+ The strwinerror function does not change the current setting
+ of GetLastError. */
+
+char *
+strwinerror (DWORD error)
{
- collect_register (r, ((char *) &th->context) + mappings[r]);
+ static char buf[1024];
+ TCHAR *msgbuf;
+ DWORD lasterr = GetLastError ();
+ DWORD chars = FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM
+ | FORMAT_MESSAGE_ALLOCATE_BUFFER,
+ NULL,
+ error,
+ 0, /* Default language */
+ (LPTSTR) &msgbuf,
+ 0,
+ NULL);
+ if (chars != 0)
+ {
+ /* If there is an \r\n appended, zap it. */
+ if (chars >= 2
+ && msgbuf[chars - 2] == '\r'
+ && msgbuf[chars - 1] == '\n')
+ {
+ chars -= 2;
+ msgbuf[chars] = 0;
+ }
+
+ if (chars > ((COUNTOF (buf)) - 1))
+ {
+ chars = COUNTOF (buf) - 1;
+ msgbuf [chars] = 0;
+ }
+
+#ifdef UNICODE
+ wcstombs (buf, msgbuf, chars + 1);
+#else
+ strncpy (buf, msgbuf, chars + 1);
+#endif
+ LocalFree (msgbuf);
+ }
+ else
+ sprintf (buf, "unknown win32 error (%u)", (unsigned) error);
+
+ SetLastError (lasterr);
+ return buf;
}
-/* Store a new register value into the current thread context. We don't
- change the program's context until later, when we resume it. */
-static void
-child_store_inferior_registers (int r)
+static BOOL
+create_process (const char *program, char *args,
+ DWORD flags, PROCESS_INFORMATION *pi)
{
- int regno;
- win32_thread_info *th = thread_rec (current_inferior_tid (), TRUE);
- if (r == -1 || r == 0 || r > NUM_REGS)
- child_store_inferior_registers (NUM_REGS);
- else
- for (regno = 0; regno < r; regno++)
- do_child_store_inferior_registers (th, regno);
+ BOOL ret;
+
+#ifdef _WIN32_WCE
+ wchar_t *p, *wprogram, *wargs;
+ size_t argslen;
+
+ wprogram = alloca ((strlen (program) + 1) * sizeof (wchar_t));
+ mbstowcs (wprogram, program, strlen (program) + 1);
+
+ for (p = wprogram; *p; ++p)
+ if (L'/' == *p)
+ *p = L'\\';
+
+ argslen = strlen (args);
+ wargs = alloca ((argslen + 1) * sizeof (wchar_t));
+ mbstowcs (wargs, args, argslen + 1);
+
+ ret = CreateProcessW (wprogram, /* image name */
+ wargs, /* command line */
+ NULL, /* security, not supported */
+ NULL, /* thread, not supported */
+ FALSE, /* inherit handles, not supported */
+ flags, /* start flags */
+ NULL, /* environment, not supported */
+ NULL, /* current directory, not supported */
+ NULL, /* start info, not supported */
+ pi); /* proc info */
+#else
+ STARTUPINFOA si = { sizeof (STARTUPINFOA) };
+
+ ret = CreateProcessA (program, /* image name */
+ args, /* command line */
+ NULL, /* security */
+ NULL, /* thread */
+ TRUE, /* inherit handles */
+ flags, /* start flags */
+ NULL, /* environment */
+ NULL, /* current directory */
+ &si, /* start info */
+ pi); /* proc info */
+#endif
+
+ return ret;
}
/* Start a new process.
@@ -448,24 +617,23 @@ static int
win32_create_inferior (char *program, char **program_args)
{
#ifndef USE_WIN32API
- char real_path[MAXPATHLEN];
+ char real_path[PATH_MAX];
char *orig_path, *new_path, *path_ptr;
#endif
- char *winenv = NULL;
- STARTUPINFO si;
- PROCESS_INFORMATION pi;
BOOL ret;
DWORD flags;
char *args;
int argslen;
int argc;
+ PROCESS_INFORMATION pi;
+ DWORD err;
+
+ /* win32_wait needs to know we're not attaching. */
+ attaching = 0;
if (!program)
error ("No executable specified, specify executable to debug.\n");
- memset (&si, 0, sizeof (si));
- si.cb = sizeof (si);
-
flags = DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS;
#ifndef USE_WIN32API
@@ -473,39 +641,44 @@ win32_create_inferior (char *program, char **program_args)
path_ptr = getenv ("PATH");
if (path_ptr)
{
+ int size = cygwin_conv_path_list (CCP_POSIX_TO_WIN_A, path_ptr, NULL, 0);
orig_path = alloca (strlen (path_ptr) + 1);
- new_path = alloca (cygwin_posix_to_win32_path_list_buf_size (path_ptr));
+ new_path = alloca (size);
strcpy (orig_path, path_ptr);
- cygwin_posix_to_win32_path_list (path_ptr, new_path);
+ cygwin_conv_path_list (CCP_POSIX_TO_WIN_A, path_ptr, new_path, size);
setenv ("PATH", new_path, 1);
- }
- cygwin_conv_to_win32_path (program, real_path);
+ }
+ cygwin_conv_path (CCP_POSIX_TO_WIN_A, program, real_path, PATH_MAX);
program = real_path;
#endif
- argslen = strlen (program) + 1;
+ argslen = 1;
for (argc = 1; program_args[argc]; argc++)
argslen += strlen (program_args[argc]) + 1;
- args = alloca (argslen);
- strcpy (args, program);
+ args = (char *) alloca (argslen);
+ args[0] = '\0';
for (argc = 1; program_args[argc]; argc++)
{
/* FIXME: Can we do better about quoting? How does Cygwin
- handle this? */
+ handle this? */
strcat (args, " ");
strcat (args, program_args[argc]);
}
- OUTMSG2 (("Command line is %s\n", args));
+ OUTMSG2 (("Command line is \"%s\"\n", args));
+#ifdef CREATE_NEW_PROCESS_GROUP
flags |= CREATE_NEW_PROCESS_GROUP;
+#endif
- ret = CreateProcess (0, args, /* command line */
- NULL, /* Security */
- NULL, /* thread */
- TRUE, /* inherit handles */
- flags, /* start flags */
- winenv, NULL, /* current directory */
- &si, &pi);
+ ret = create_process (program, args, flags, &pi);
+ err = GetLastError ();
+ if (!ret && err == ERROR_FILE_NOT_FOUND)
+ {
+ char *exename = (char *) alloca (strlen (program) + 5);
+ strcat (strcpy (exename, program), ".exe");
+ ret = create_process (exename, args, flags, &pi);
+ err = GetLastError ();
+ }
#ifndef USE_WIN32API
if (orig_path)
@@ -514,20 +687,22 @@ win32_create_inferior (char *program, char **program_args)
if (!ret)
{
- error ("Error creating process %s, (error %d): %s\n", args,
- (int) GetLastError (), strerror (GetLastError ()));
+ error ("Error creating process \"%s%s\", (error %d): %s\n",
+ program, args, (int) err, strwinerror (err));
}
else
{
OUTMSG2 (("Process created: %s\n", (char *) args));
}
+#ifndef _WIN32_WCE
+ /* On Windows CE this handle can't be closed. The OS reuses
+ it in the debug events, while the 9x/NT versions of Windows
+ probably use a DuplicateHandle'd one. */
CloseHandle (pi.hThread);
+#endif
- current_process_handle = pi.hProcess;
- current_process_id = pi.dwProcessId;
-
- do_initial_child_stuff (current_process_id);
+ do_initial_child_stuff (pi.hProcess, pi.dwProcessId, 0);
return current_process_id;
}
@@ -538,47 +713,41 @@ win32_create_inferior (char *program, char **program_args)
static int
win32_attach (unsigned long pid)
{
- int res = 0;
- HMODULE kernel32 = LoadLibrary ("KERNEL32.DLL");
- winapi_DebugActiveProcessStop *DebugActiveProcessStop = NULL;
- winapi_DebugSetProcessKillOnExit *DebugSetProcessKillOnExit = NULL;
-
- DebugActiveProcessStop =
- (winapi_DebugActiveProcessStop *) GetProcAddress (kernel32,
- "DebugActiveProcessStop");
- DebugSetProcessKillOnExit =
- (winapi_DebugSetProcessKillOnExit *) GetProcAddress (kernel32,
- "DebugSetProcessKillOnExit");
-
- res = DebugActiveProcess (pid) ? 1 : 0;
-
- if (!res)
- error ("Attach to process failed.");
-
- if (DebugSetProcessKillOnExit != NULL)
- DebugSetProcessKillOnExit (FALSE);
-
- current_process_id = pid;
- current_process_handle = OpenProcess (PROCESS_ALL_ACCESS, FALSE, pid);
+ HANDLE h;
+ winapi_DebugSetProcessKillOnExit DebugSetProcessKillOnExit = NULL;
+ DWORD err;
+#ifdef _WIN32_WCE
+ HMODULE dll = GetModuleHandle (_T("COREDLL.DLL"));
+#else
+ HMODULE dll = GetModuleHandle (_T("KERNEL32.DLL"));
+#endif
+ DebugSetProcessKillOnExit = GETPROCADDRESS (dll, DebugSetProcessKillOnExit);
- if (current_process_handle == NULL)
+ h = OpenProcess (PROCESS_ALL_ACCESS, FALSE, pid);
+ if (h != NULL)
{
- res = 0;
- if (DebugActiveProcessStop != NULL)
- DebugActiveProcessStop (current_process_id);
- }
+ if (DebugActiveProcess (pid))
+ {
+ if (DebugSetProcessKillOnExit != NULL)
+ DebugSetProcessKillOnExit (FALSE);
- if (res)
- do_initial_child_stuff (pid);
+ /* win32_wait needs to know we're attaching. */
+ attaching = 1;
+ do_initial_child_stuff (h, pid, 1);
+ return 0;
+ }
- FreeLibrary (kernel32);
+ CloseHandle (h);
+ }
- return res;
+ err = GetLastError ();
+ error ("Attach to process failed (error %d): %s\n",
+ (int) err, strwinerror (err));
}
/* Handle OUTPUT_DEBUG_STRING_EVENT from child process. */
static void
-handle_output_debug_string (struct target_waitstatus *ourstatus)
+handle_output_debug_string (void)
{
#define READ_BUFFER_LEN 1024
CORE_ADDR addr;
@@ -596,7 +765,7 @@ handle_output_debug_string (struct target_waitstatus *ourstatus)
if (current_event.u.DebugString.fUnicode)
{
/* The event tells us how many bytes, not chars, even
- in Unicode. */
+ in Unicode. */
WCHAR buffer[(READ_BUFFER_LEN + 1) / sizeof (WCHAR)] = { 0 };
if (read_inferior_memory (addr, (unsigned char *) buffer, nbytes) != 0)
return;
@@ -608,17 +777,37 @@ handle_output_debug_string (struct target_waitstatus *ourstatus)
return;
}
- if (strncmp (s, "cYg", 3) != 0)
- monitor_output (s);
+ if (!startswith (s, "cYg"))
+ {
+ if (!server_waiting)
+ {
+ OUTMSG2(("%s", s));
+ return;
+ }
+
+ monitor_output (s);
+ }
#undef READ_BUFFER_LEN
}
-/* Kill all inferiors. */
static void
-win32_kill (void)
+win32_clear_inferiors (void)
+{
+ if (current_process_handle != NULL)
+ CloseHandle (current_process_handle);
+
+ for_each_inferior (&all_threads, delete_thread_info);
+ clear_inferiors ();
+}
+
+/* Kill all inferiors. */
+static int
+win32_kill (int pid)
{
+ struct process_info *process;
+
if (current_process_handle == NULL)
- return;
+ return -1;
TerminateProcess (current_process_handle, 0);
for (;;)
@@ -630,48 +819,81 @@ win32_kill (void)
if (current_event.dwDebugEventCode == EXIT_PROCESS_DEBUG_EVENT)
break;
else if (current_event.dwDebugEventCode == OUTPUT_DEBUG_STRING_EVENT)
- {
- struct target_waitstatus our_status = { 0 };
- handle_output_debug_string (&our_status);
- }
+ handle_output_debug_string ();
}
+
+ win32_clear_inferiors ();
+
+ process = find_process_pid (pid);
+ remove_process (process);
+ return 0;
+}
+
+/* Detach from inferior PID. */
+static int
+win32_detach (int pid)
+{
+ struct process_info *process;
+ winapi_DebugActiveProcessStop DebugActiveProcessStop = NULL;
+ winapi_DebugSetProcessKillOnExit DebugSetProcessKillOnExit = NULL;
+#ifdef _WIN32_WCE
+ HMODULE dll = GetModuleHandle (_T("COREDLL.DLL"));
+#else
+ HMODULE dll = GetModuleHandle (_T("KERNEL32.DLL"));
+#endif
+ DebugActiveProcessStop = GETPROCADDRESS (dll, DebugActiveProcessStop);
+ DebugSetProcessKillOnExit = GETPROCADDRESS (dll, DebugSetProcessKillOnExit);
+
+ if (DebugSetProcessKillOnExit == NULL
+ || DebugActiveProcessStop == NULL)
+ return -1;
+
+ {
+ struct thread_resume resume;
+ resume.thread = minus_one_ptid;
+ resume.kind = resume_continue;
+ resume.sig = 0;
+ win32_resume (&resume, 1);
+ }
+
+ if (!DebugActiveProcessStop (current_process_id))
+ return -1;
+
+ DebugSetProcessKillOnExit (FALSE);
+ process = find_process_pid (pid);
+ remove_process (process);
+
+ win32_clear_inferiors ();
+ return 0;
}
-/* Detach from all inferiors. */
static void
-win32_detach (void)
+win32_mourn (struct process_info *process)
{
- HMODULE kernel32 = LoadLibrary ("KERNEL32.DLL");
- winapi_DebugActiveProcessStop *DebugActiveProcessStop = NULL;
- winapi_DebugSetProcessKillOnExit *DebugSetProcessKillOnExit = NULL;
-
- DebugActiveProcessStop =
- (winapi_DebugActiveProcessStop *) GetProcAddress (kernel32,
- "DebugActiveProcessStop");
- DebugSetProcessKillOnExit =
- (winapi_DebugSetProcessKillOnExit *) GetProcAddress (kernel32,
- "DebugSetProcessKillOnExit");
-
- if (DebugSetProcessKillOnExit != NULL)
- DebugSetProcessKillOnExit (FALSE);
-
- if (DebugActiveProcessStop != NULL)
- DebugActiveProcessStop (current_process_id);
- else
- win32_kill ();
+ remove_process (process);
+}
- FreeLibrary (kernel32);
+/* Wait for inferiors to end. */
+static void
+win32_join (int pid)
+{
+ HANDLE h = OpenProcess (PROCESS_ALL_ACCESS, FALSE, pid);
+ if (h != NULL)
+ {
+ WaitForSingleObject (h, INFINITE);
+ CloseHandle (h);
+ }
}
/* Return 1 iff the thread with thread ID TID is alive. */
static int
-win32_thread_alive (unsigned long tid)
+win32_thread_alive (ptid_t ptid)
{
int res;
/* Our thread list is reliable; don't bother to poll target
threads. */
- if (find_inferior_id (&all_threads, tid) != NULL)
+ if (find_inferior_id (&all_threads, ptid) != NULL)
res = 1;
else
res = 0;
@@ -681,76 +903,77 @@ win32_thread_alive (unsigned long tid)
/* Resume the inferior process. RESUME_INFO describes how we want
to resume. */
static void
-win32_resume (struct thread_resume *resume_info)
+win32_resume (struct thread_resume *resume_info, size_t n)
{
DWORD tid;
- enum target_signal sig;
+ enum gdb_signal sig;
int step;
win32_thread_info *th;
DWORD continue_status = DBG_CONTINUE;
+ ptid_t ptid;
/* This handles the very limited set of resume packets that GDB can
currently produce. */
- if (resume_info[0].thread == -1)
+ if (n == 1 && ptid_equal (resume_info[0].thread, minus_one_ptid))
tid = -1;
- else if (resume_info[1].thread == -1 && !resume_info[1].leave_stopped)
+ else if (n > 1)
tid = -1;
else
/* Yes, we're ignoring resume_info[0].thread. It'd be tricky to make
the Windows resume code do the right thing for thread switching. */
tid = current_event.dwThreadId;
- if (resume_info[0].thread != -1)
+ if (!ptid_equal (resume_info[0].thread, minus_one_ptid))
{
- sig = resume_info[0].sig;
- step = resume_info[0].step;
+ sig = gdb_signal_from_host (resume_info[0].sig);
+ step = resume_info[0].kind == resume_step;
}
else
{
- sig = 0;
+ sig = GDB_SIGNAL_0;
step = 0;
}
- if (sig != TARGET_SIGNAL_0)
+ if (sig != GDB_SIGNAL_0)
{
if (current_event.dwDebugEventCode != EXCEPTION_DEBUG_EVENT)
{
- OUTMSG (("Cannot continue with signal %d here.\n", sig));
+ OUTMSG (("Cannot continue with signal %s here.\n",
+ gdb_signal_to_string (sig)));
}
else if (sig == last_sig)
continue_status = DBG_EXCEPTION_NOT_HANDLED;
else
- OUTMSG (("Can only continue with recieved signal %d.\n", last_sig));
+ OUTMSG (("Can only continue with received signal %s.\n",
+ gdb_signal_to_string (last_sig)));
}
- last_sig = TARGET_SIGNAL_0;
+ last_sig = GDB_SIGNAL_0;
/* Get context for the currently selected thread. */
- th = thread_rec (current_event.dwThreadId, FALSE);
+ ptid = debug_event_ptid (¤t_event);
+ th = thread_rec (ptid, FALSE);
if (th)
{
+ win32_prepare_to_resume (th);
+
if (th->context.ContextFlags)
{
- if (debug_registers_changed)
- {
- th->context.Dr0 = dr[0];
- th->context.Dr1 = dr[1];
- th->context.Dr2 = dr[2];
- th->context.Dr3 = dr[3];
- /* th->context.Dr6 = dr[6];
- FIXME: should we set dr6 also ?? */
- th->context.Dr7 = dr[7];
- }
-
/* Move register values from the inferior into the thread
context structure. */
regcache_invalidate ();
if (step)
- th->context.EFlags |= FLAG_TRACE_BIT;
+ {
+ if (the_low_target.single_step != NULL)
+ (*the_low_target.single_step) (th);
+ else
+ error ("Single stepping is not supported "
+ "in this configuration.\n");
+ }
- SetThreadContext (th->h, &th->context);
+ win32_set_thread_context (th);
th->context.ContextFlags = 0;
}
}
@@ -761,163 +984,510 @@ win32_resume (struct thread_resume *resume_info)
child_continue (continue_status, tid);
}
-static int
+static void
+win32_add_one_solib (const char *name, CORE_ADDR load_addr)
+{
+ char buf[MAX_PATH + 1];
+ char buf2[MAX_PATH + 1];
+
+#ifdef _WIN32_WCE
+ WIN32_FIND_DATA w32_fd;
+ WCHAR wname[MAX_PATH + 1];
+ mbstowcs (wname, name, MAX_PATH);
+ HANDLE h = FindFirstFile (wname, &w32_fd);
+#else
+ WIN32_FIND_DATAA w32_fd;
+ HANDLE h = FindFirstFileA (name, &w32_fd);
+#endif
+
+ /* The symbols in a dll are offset by 0x1000, which is the
+ offset from 0 of the first byte in an image - because
+ of the file header and the section alignment. */
+ load_addr += 0x1000;
+
+ if (h == INVALID_HANDLE_VALUE)
+ strcpy (buf, name);
+ else
+ {
+ FindClose (h);
+ strcpy (buf, name);
+#ifndef _WIN32_WCE
+ {
+ char cwd[MAX_PATH + 1];
+ char *p;
+ if (GetCurrentDirectoryA (MAX_PATH + 1, cwd))
+ {
+ p = strrchr (buf, '\\');
+ if (p)
+ p[1] = '\0';
+ SetCurrentDirectoryA (buf);
+ GetFullPathNameA (w32_fd.cFileName, MAX_PATH, buf, &p);
+ SetCurrentDirectoryA (cwd);
+ }
+ }
+#endif
+ }
+
+#ifndef _WIN32_WCE
+ if (strcasecmp (buf, "ntdll.dll") == 0)
+ {
+ GetSystemDirectoryA (buf, sizeof (buf));
+ strcat (buf, "\\ntdll.dll");
+ }
+#endif
+
+#ifdef __CYGWIN__
+ cygwin_conv_path (CCP_WIN_A_TO_POSIX, buf, buf2, sizeof (buf2));
+#else
+ strcpy (buf2, buf);
+#endif
+
+ loaded_dll (buf2, load_addr);
+}
+
+static char *
+get_image_name (HANDLE h, void *address, int unicode)
+{
+ static char buf[(2 * MAX_PATH) + 1];
+ DWORD size = unicode ? sizeof (WCHAR) : sizeof (char);
+ char *address_ptr;
+ int len = 0;
+ char b[2];
+ SIZE_T done;
+
+ /* Attempt to read the name of the dll that was detected.
+ This is documented to work only when actively debugging
+ a program. It will not work for attached processes. */
+ if (address == NULL)
+ return NULL;
+
+#ifdef _WIN32_WCE
+ /* Windows CE reports the address of the image name,
+ instead of an address of a pointer into the image name. */
+ address_ptr = address;
+#else
+ /* See if we could read the address of a string, and that the
+ address isn't null. */
+ if (!ReadProcessMemory (h, address, &address_ptr,
+ sizeof (address_ptr), &done)
+ || done != sizeof (address_ptr)
+ || !address_ptr)
+ return NULL;
+#endif
+
+ /* Find the length of the string */
+ while (ReadProcessMemory (h, address_ptr + len++ * size, &b, size, &done)
+ && (b[0] != 0 || b[size - 1] != 0) && done == size)
+ continue;
+
+ if (!unicode)
+ ReadProcessMemory (h, address_ptr, buf, len, &done);
+ else
+ {
+ WCHAR *unicode_address = XALLOCAVEC (WCHAR, len);
+ ReadProcessMemory (h, address_ptr, unicode_address, len * sizeof (WCHAR),
+ &done);
+
+ WideCharToMultiByte (CP_ACP, 0, unicode_address, len, buf, len, 0, 0);
+ }
+
+ return buf;
+}
+
+typedef BOOL (WINAPI *winapi_EnumProcessModules) (HANDLE, HMODULE *,
+ DWORD, LPDWORD);
+typedef BOOL (WINAPI *winapi_GetModuleInformation) (HANDLE, HMODULE,
+ LPMODULEINFO, DWORD);
+typedef DWORD (WINAPI *winapi_GetModuleFileNameExA) (HANDLE, HMODULE,
+ LPSTR, DWORD);
+
+static winapi_EnumProcessModules win32_EnumProcessModules;
+static winapi_GetModuleInformation win32_GetModuleInformation;
+static winapi_GetModuleFileNameExA win32_GetModuleFileNameExA;
+
+static BOOL
+load_psapi (void)
+{
+ static int psapi_loaded = 0;
+ static HMODULE dll = NULL;
+
+ if (!psapi_loaded)
+ {
+ psapi_loaded = 1;
+ dll = LoadLibrary (TEXT("psapi.dll"));
+ if (!dll)
+ return FALSE;
+ win32_EnumProcessModules =
+ GETPROCADDRESS (dll, EnumProcessModules);
+ win32_GetModuleInformation =
+ GETPROCADDRESS (dll, GetModuleInformation);
+ win32_GetModuleFileNameExA =
+ GETPROCADDRESS (dll, GetModuleFileNameExA);
+ }
+
+ return (win32_EnumProcessModules != NULL
+ && win32_GetModuleInformation != NULL
+ && win32_GetModuleFileNameExA != NULL);
+}
+
+#ifndef _WIN32_WCE
+
+/* Iterate over all DLLs currently mapped by our inferior, and
+ add them to our list of solibs. */
+
+static void
+win32_add_all_dlls (void)
+{
+ size_t i;
+ HMODULE dh_buf[1];
+ HMODULE *DllHandle = dh_buf;
+ DWORD cbNeeded;
+ BOOL ok;
+
+ if (!load_psapi ())
+ return;
+
+ cbNeeded = 0;
+ ok = (*win32_EnumProcessModules) (current_process_handle,
+ DllHandle,
+ sizeof (HMODULE),
+ &cbNeeded);
+
+ if (!ok || !cbNeeded)
+ return;
+
+ DllHandle = (HMODULE *) alloca (cbNeeded);
+ if (!DllHandle)
+ return;
+
+ ok = (*win32_EnumProcessModules) (current_process_handle,
+ DllHandle,
+ cbNeeded,
+ &cbNeeded);
+ if (!ok)
+ return;
+
+ for (i = 1; i < ((size_t) cbNeeded / sizeof (HMODULE)); i++)
+ {
+ MODULEINFO mi;
+ char dll_name[MAX_PATH];
+
+ if (!(*win32_GetModuleInformation) (current_process_handle,
+ DllHandle[i],
+ &mi,
+ sizeof (mi)))
+ continue;
+ if ((*win32_GetModuleFileNameExA) (current_process_handle,
+ DllHandle[i],
+ dll_name,
+ MAX_PATH) == 0)
+ continue;
+ win32_add_one_solib (dll_name, (CORE_ADDR) (uintptr_t) mi.lpBaseOfDll);
+ }
+}
+#endif
+
+typedef HANDLE (WINAPI *winapi_CreateToolhelp32Snapshot) (DWORD, DWORD);
+typedef BOOL (WINAPI *winapi_Module32First) (HANDLE, LPMODULEENTRY32);
+typedef BOOL (WINAPI *winapi_Module32Next) (HANDLE, LPMODULEENTRY32);
+
+/* Handle a DLL load event.
+
+ This function assumes that this event did not occur during inferior
+ initialization, where their event info may be incomplete (see
+ do_initial_child_stuff and win32_add_all_dlls for more info on
+ how we handle DLL loading during that phase). */
+
+static void
+handle_load_dll (void)
+{
+ LOAD_DLL_DEBUG_INFO *event = ¤t_event.u.LoadDll;
+ char *dll_name;
+
+ dll_name = get_image_name (current_process_handle,
+ event->lpImageName, event->fUnicode);
+ if (!dll_name)
+ return;
+
+ win32_add_one_solib (dll_name, (CORE_ADDR) (uintptr_t) event->lpBaseOfDll);
+}
+
+/* Handle a DLL unload event.
+
+ This function assumes that this event did not occur during inferior
+ initialization, where their event info may be incomplete (see
+ do_initial_child_stuff and win32_add_one_solib for more info
+ on how we handle DLL loading during that phase). */
+
+static void
+handle_unload_dll (void)
+{
+ CORE_ADDR load_addr =
+ (CORE_ADDR) (uintptr_t) current_event.u.UnloadDll.lpBaseOfDll;
+
+ /* The symbols in a dll are offset by 0x1000, which is the
+ offset from 0 of the first byte in an image - because
+ of the file header and the section alignment. */
+ load_addr += 0x1000;
+ unloaded_dll (NULL, load_addr);
+}
+
+static void
handle_exception (struct target_waitstatus *ourstatus)
{
- win32_thread_info *th;
DWORD code = current_event.u.Exception.ExceptionRecord.ExceptionCode;
ourstatus->kind = TARGET_WAITKIND_STOPPED;
- /* Record the context of the current thread. */
- th = thread_rec (current_event.dwThreadId, -1);
-
switch (code)
{
case EXCEPTION_ACCESS_VIOLATION:
OUTMSG2 (("EXCEPTION_ACCESS_VIOLATION"));
- ourstatus->value.sig = TARGET_SIGNAL_SEGV;
+ ourstatus->value.sig = GDB_SIGNAL_SEGV;
break;
case STATUS_STACK_OVERFLOW:
OUTMSG2 (("STATUS_STACK_OVERFLOW"));
- ourstatus->value.sig = TARGET_SIGNAL_SEGV;
+ ourstatus->value.sig = GDB_SIGNAL_SEGV;
break;
case STATUS_FLOAT_DENORMAL_OPERAND:
OUTMSG2 (("STATUS_FLOAT_DENORMAL_OPERAND"));
- ourstatus->value.sig = TARGET_SIGNAL_FPE;
+ ourstatus->value.sig = GDB_SIGNAL_FPE;
break;
case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
OUTMSG2 (("EXCEPTION_ARRAY_BOUNDS_EXCEEDED"));
- ourstatus->value.sig = TARGET_SIGNAL_FPE;
+ ourstatus->value.sig = GDB_SIGNAL_FPE;
break;
case STATUS_FLOAT_INEXACT_RESULT:
OUTMSG2 (("STATUS_FLOAT_INEXACT_RESULT"));
- ourstatus->value.sig = TARGET_SIGNAL_FPE;
+ ourstatus->value.sig = GDB_SIGNAL_FPE;
break;
case STATUS_FLOAT_INVALID_OPERATION:
OUTMSG2 (("STATUS_FLOAT_INVALID_OPERATION"));
- ourstatus->value.sig = TARGET_SIGNAL_FPE;
+ ourstatus->value.sig = GDB_SIGNAL_FPE;
break;
case STATUS_FLOAT_OVERFLOW:
OUTMSG2 (("STATUS_FLOAT_OVERFLOW"));
- ourstatus->value.sig = TARGET_SIGNAL_FPE;
+ ourstatus->value.sig = GDB_SIGNAL_FPE;
break;
case STATUS_FLOAT_STACK_CHECK:
OUTMSG2 (("STATUS_FLOAT_STACK_CHECK"));
- ourstatus->value.sig = TARGET_SIGNAL_FPE;
+ ourstatus->value.sig = GDB_SIGNAL_FPE;
break;
case STATUS_FLOAT_UNDERFLOW:
OUTMSG2 (("STATUS_FLOAT_UNDERFLOW"));
- ourstatus->value.sig = TARGET_SIGNAL_FPE;
+ ourstatus->value.sig = GDB_SIGNAL_FPE;
break;
case STATUS_FLOAT_DIVIDE_BY_ZERO:
OUTMSG2 (("STATUS_FLOAT_DIVIDE_BY_ZERO"));
- ourstatus->value.sig = TARGET_SIGNAL_FPE;
+ ourstatus->value.sig = GDB_SIGNAL_FPE;
break;
case STATUS_INTEGER_DIVIDE_BY_ZERO:
OUTMSG2 (("STATUS_INTEGER_DIVIDE_BY_ZERO"));
- ourstatus->value.sig = TARGET_SIGNAL_FPE;
+ ourstatus->value.sig = GDB_SIGNAL_FPE;
break;
case STATUS_INTEGER_OVERFLOW:
OUTMSG2 (("STATUS_INTEGER_OVERFLOW"));
- ourstatus->value.sig = TARGET_SIGNAL_FPE;
+ ourstatus->value.sig = GDB_SIGNAL_FPE;
break;
case EXCEPTION_BREAKPOINT:
OUTMSG2 (("EXCEPTION_BREAKPOINT"));
- ourstatus->value.sig = TARGET_SIGNAL_TRAP;
+ ourstatus->value.sig = GDB_SIGNAL_TRAP;
+#ifdef _WIN32_WCE
+ /* Remove the initial breakpoint. */
+ check_breakpoints ((CORE_ADDR) (long) current_event
+ .u.Exception.ExceptionRecord.ExceptionAddress);
+#endif
break;
case DBG_CONTROL_C:
OUTMSG2 (("DBG_CONTROL_C"));
- ourstatus->value.sig = TARGET_SIGNAL_INT;
+ ourstatus->value.sig = GDB_SIGNAL_INT;
break;
case DBG_CONTROL_BREAK:
OUTMSG2 (("DBG_CONTROL_BREAK"));
- ourstatus->value.sig = TARGET_SIGNAL_INT;
+ ourstatus->value.sig = GDB_SIGNAL_INT;
break;
case EXCEPTION_SINGLE_STEP:
OUTMSG2 (("EXCEPTION_SINGLE_STEP"));
- ourstatus->value.sig = TARGET_SIGNAL_TRAP;
+ ourstatus->value.sig = GDB_SIGNAL_TRAP;
break;
case EXCEPTION_ILLEGAL_INSTRUCTION:
OUTMSG2 (("EXCEPTION_ILLEGAL_INSTRUCTION"));
- ourstatus->value.sig = TARGET_SIGNAL_ILL;
+ ourstatus->value.sig = GDB_SIGNAL_ILL;
break;
case EXCEPTION_PRIV_INSTRUCTION:
OUTMSG2 (("EXCEPTION_PRIV_INSTRUCTION"));
- ourstatus->value.sig = TARGET_SIGNAL_ILL;
+ ourstatus->value.sig = GDB_SIGNAL_ILL;
break;
case EXCEPTION_NONCONTINUABLE_EXCEPTION:
OUTMSG2 (("EXCEPTION_NONCONTINUABLE_EXCEPTION"));
- ourstatus->value.sig = TARGET_SIGNAL_ILL;
+ ourstatus->value.sig = GDB_SIGNAL_ILL;
break;
default:
if (current_event.u.Exception.dwFirstChance)
- return 0;
- OUTMSG2 (("gdbserver: unknown target exception 0x%08lx at 0x%08lx",
- current_event.u.Exception.ExceptionRecord.ExceptionCode,
- (DWORD) current_event.u.Exception.ExceptionRecord.
- ExceptionAddress));
- ourstatus->value.sig = TARGET_SIGNAL_UNKNOWN;
+ {
+ ourstatus->kind = TARGET_WAITKIND_SPURIOUS;
+ return;
+ }
+ OUTMSG2 (("gdbserver: unknown target exception 0x%08x at 0x%s",
+ (unsigned) current_event.u.Exception.ExceptionRecord.ExceptionCode,
+ phex_nz ((uintptr_t) current_event.u.Exception.ExceptionRecord.
+ ExceptionAddress, sizeof (uintptr_t))));
+ ourstatus->value.sig = GDB_SIGNAL_UNKNOWN;
break;
}
OUTMSG2 (("\n"));
last_sig = ourstatus->value.sig;
+}
+
+
+static void
+suspend_one_thread (struct inferior_list_entry *entry)
+{
+ struct thread_info *thread = (struct thread_info *) entry;
+ win32_thread_info *th = (win32_thread_info *) inferior_target_data (thread);
+
+ if (!th->suspended)
+ {
+ if (SuspendThread (th->h) == (DWORD) -1)
+ {
+ DWORD err = GetLastError ();
+ OUTMSG (("warning: SuspendThread failed in suspend_one_thread, "
+ "(error %d): %s\n", (int) err, strwinerror (err)));
+ }
+ else
+ th->suspended = 1;
+ }
+}
+
+static void
+fake_breakpoint_event (void)
+{
+ OUTMSG2(("fake_breakpoint_event\n"));
+
+ faked_breakpoint = 1;
+
+ memset (¤t_event, 0, sizeof (current_event));
+ current_event.dwThreadId = main_thread_id;
+ current_event.dwDebugEventCode = EXCEPTION_DEBUG_EVENT;
+ current_event.u.Exception.ExceptionRecord.ExceptionCode
+ = EXCEPTION_BREAKPOINT;
+
+ for_each_inferior (&all_threads, suspend_one_thread);
+}
+
+#ifdef _WIN32_WCE
+static int
+auto_delete_breakpoint (CORE_ADDR stop_pc)
+{
return 1;
}
+#endif
+
+/* Get the next event from the child. */
-/* Get the next event from the child. Return 1 if the event requires
- handling. */
static int
get_child_debug_event (struct target_waitstatus *ourstatus)
{
- BOOL debug_event;
- DWORD continue_status, event_code;
- win32_thread_info *th = NULL;
- static win32_thread_info dummy_thread_info;
- int retval = 0;
+ ptid_t ptid;
-in:
-
- last_sig = TARGET_SIGNAL_0;
+ last_sig = GDB_SIGNAL_0;
ourstatus->kind = TARGET_WAITKIND_SPURIOUS;
- if (!(debug_event = WaitForDebugEvent (¤t_event, 1000)))
- goto out;
+ /* Check if GDB sent us an interrupt request. */
+ check_remote_input_interrupt_request ();
+
+ if (soft_interrupt_requested)
+ {
+ soft_interrupt_requested = 0;
+ fake_breakpoint_event ();
+ goto gotevent;
+ }
+
+#ifndef _WIN32_WCE
+ attaching = 0;
+#else
+ if (attaching)
+ {
+ /* WinCE doesn't set an initial breakpoint automatically. To
+ stop the inferior, we flush all currently pending debug
+ events -- the thread list and the dll list are always
+ reported immediatelly without delay, then, we suspend all
+ threads and pretend we saw a trap at the current PC of the
+ main thread.
+
+ Contrary to desktop Windows, Windows CE *does* report the dll
+ names on LOAD_DLL_DEBUG_EVENTs resulting from a
+ DebugActiveProcess call. This limits the way we can detect
+ if all the dlls have already been reported. If we get a real
+ debug event before leaving attaching, the worst that will
+ happen is the user will see a spurious breakpoint. */
+
+ current_event.dwDebugEventCode = 0;
+ if (!WaitForDebugEvent (¤t_event, 0))
+ {
+ OUTMSG2(("no attach events left\n"));
+ fake_breakpoint_event ();
+ attaching = 0;
+ }
+ else
+ OUTMSG2(("got attach event\n"));
+ }
+ else
+#endif
+ {
+ /* Keep the wait time low enough for confortable remote
+ interruption, but high enough so gdbserver doesn't become a
+ bottleneck. */
+ if (!WaitForDebugEvent (¤t_event, 250))
+ {
+ DWORD e = GetLastError();
+
+ if (e == ERROR_PIPE_NOT_CONNECTED)
+ {
+ /* This will happen if the loader fails to succesfully
+ load the application, e.g., if the main executable
+ tries to pull in a non-existing export from a
+ DLL. */
+ ourstatus->kind = TARGET_WAITKIND_EXITED;
+ ourstatus->value.integer = 1;
+ return 1;
+ }
- current_inferior =
- (struct thread_info *) find_inferior_id (&all_threads,
- current_event.dwThreadId);
+ return 0;
+ }
+ }
- continue_status = DBG_CONTINUE;
- event_code = current_event.dwDebugEventCode;
+ gotevent:
- switch (event_code)
+ switch (current_event.dwDebugEventCode)
{
case CREATE_THREAD_DEBUG_EVENT:
OUTMSG2 (("gdbserver: kernel event CREATE_THREAD_DEBUG_EVENT "
- "for pid=%d tid=%x)\n",
+ "for pid=%u tid=%x)\n",
(unsigned) current_event.dwProcessId,
(unsigned) current_event.dwThreadId));
/* Record the existence of this thread. */
- th = child_add_thread (current_event.dwThreadId,
- current_event.u.CreateThread.hThread);
-
- retval = current_event.dwThreadId;
+ child_add_thread (current_event.dwProcessId,
+ current_event.dwThreadId,
+ current_event.u.CreateThread.hThread,
+ current_event.u.CreateThread.lpThreadLocalBase);
break;
case EXIT_THREAD_DEBUG_EVENT:
OUTMSG2 (("gdbserver: kernel event EXIT_THREAD_DEBUG_EVENT "
- "for pid=%d tid=%x\n",
+ "for pid=%u tid=%x\n",
(unsigned) current_event.dwProcessId,
(unsigned) current_event.dwThreadId));
- child_delete_thread (current_event.dwThreadId);
- th = &dummy_thread_info;
- break;
+ child_delete_thread (current_event.dwProcessId,
+ current_event.dwThreadId);
+
+ current_thread = (struct thread_info *) all_threads.head;
+ return 1;
case CREATE_PROCESS_DEBUG_EVENT:
OUTMSG2 (("gdbserver: kernel event CREATE_PROCESS_DEBUG_EVENT "
- "for pid=%d tid=%x\n",
+ "for pid=%u tid=%x\n",
(unsigned) current_event.dwProcessId,
(unsigned) current_event.dwThreadId));
CloseHandle (current_event.u.CreateProcessInfo.hFile);
@@ -929,151 +1499,161 @@ in:
ourstatus->value.execd_pathname = "Main executable";
/* Add the main thread. */
- th =
- child_add_thread (main_thread_id,
- current_event.u.CreateProcessInfo.hThread);
-
- retval = ourstatus->value.related_pid = current_event.dwThreadId;
+ child_add_thread (current_event.dwProcessId,
+ main_thread_id,
+ current_event.u.CreateProcessInfo.hThread,
+ current_event.u.CreateProcessInfo.lpThreadLocalBase);
+
+ ourstatus->value.related_pid = debug_event_ptid (¤t_event);
+#ifdef _WIN32_WCE
+ if (!attaching)
+ {
+ /* Windows CE doesn't set the initial breakpoint
+ automatically like the desktop versions of Windows do.
+ We add it explicitly here. It will be removed as soon as
+ it is hit. */
+ set_breakpoint_at ((CORE_ADDR) (long) current_event.u
+ .CreateProcessInfo.lpStartAddress,
+ auto_delete_breakpoint);
+ }
+#endif
break;
case EXIT_PROCESS_DEBUG_EVENT:
OUTMSG2 (("gdbserver: kernel event EXIT_PROCESS_DEBUG_EVENT "
- "for pid=%d tid=%x\n",
+ "for pid=%u tid=%x\n",
(unsigned) current_event.dwProcessId,
(unsigned) current_event.dwThreadId));
ourstatus->kind = TARGET_WAITKIND_EXITED;
ourstatus->value.integer = current_event.u.ExitProcess.dwExitCode;
+ child_continue (DBG_CONTINUE, -1);
CloseHandle (current_process_handle);
current_process_handle = NULL;
- retval = main_thread_id;
break;
case LOAD_DLL_DEBUG_EVENT:
OUTMSG2 (("gdbserver: kernel event LOAD_DLL_DEBUG_EVENT "
- "for pid=%d tid=%x\n",
+ "for pid=%u tid=%x\n",
(unsigned) current_event.dwProcessId,
(unsigned) current_event.dwThreadId));
CloseHandle (current_event.u.LoadDll.hFile);
+ if (! child_initialization_done)
+ break;
+ handle_load_dll ();
ourstatus->kind = TARGET_WAITKIND_LOADED;
- ourstatus->value.integer = 0;
- retval = main_thread_id;
+ ourstatus->value.sig = GDB_SIGNAL_TRAP;
break;
case UNLOAD_DLL_DEBUG_EVENT:
OUTMSG2 (("gdbserver: kernel event UNLOAD_DLL_DEBUG_EVENT "
- "for pid=%d tid=%x\n",
+ "for pid=%u tid=%x\n",
(unsigned) current_event.dwProcessId,
(unsigned) current_event.dwThreadId));
+ if (! child_initialization_done)
+ break;
+ handle_unload_dll ();
+ ourstatus->kind = TARGET_WAITKIND_LOADED;
+ ourstatus->value.sig = GDB_SIGNAL_TRAP;
break;
case EXCEPTION_DEBUG_EVENT:
OUTMSG2 (("gdbserver: kernel event EXCEPTION_DEBUG_EVENT "
- "for pid=%d tid=%x\n",
+ "for pid=%u tid=%x\n",
(unsigned) current_event.dwProcessId,
(unsigned) current_event.dwThreadId));
- retval = handle_exception (ourstatus);
+ handle_exception (ourstatus);
break;
case OUTPUT_DEBUG_STRING_EVENT:
/* A message from the kernel (or Cygwin). */
OUTMSG2 (("gdbserver: kernel event OUTPUT_DEBUG_STRING_EVENT "
- "for pid=%d tid=%x\n",
+ "for pid=%u tid=%x\n",
(unsigned) current_event.dwProcessId,
(unsigned) current_event.dwThreadId));
- handle_output_debug_string (ourstatus);
+ handle_output_debug_string ();
break;
default:
OUTMSG2 (("gdbserver: kernel event unknown "
- "for pid=%d tid=%x code=%ld\n",
+ "for pid=%u tid=%x code=%x\n",
(unsigned) current_event.dwProcessId,
(unsigned) current_event.dwThreadId,
- current_event.dwDebugEventCode));
+ (unsigned) current_event.dwDebugEventCode));
break;
}
- current_inferior =
- (struct thread_info *) find_inferior_id (&all_threads,
- current_event.dwThreadId);
-
- if (!retval || (event_code != EXCEPTION_DEBUG_EVENT && event_code != EXIT_PROCESS_DEBUG_EVENT))
- {
- child_continue (continue_status, -1);
- goto in;
- }
-
- if (th == NULL)
- thread_rec (current_event.dwThreadId, TRUE);
-
-out:
- return retval;
+ ptid = debug_event_ptid (¤t_event);
+ current_thread =
+ (struct thread_info *) find_inferior_id (&all_threads, ptid);
+ return 1;
}
/* Wait for the inferior process to change state.
STATUS will be filled in with a response code to send to GDB.
Returns the signal which caused the process to stop. */
-static unsigned char
-win32_wait (char *status)
+static ptid_t
+win32_wait (ptid_t ptid, struct target_waitstatus *ourstatus, int options)
{
- struct target_waitstatus our_status;
+ struct regcache *regcache;
- *status = 'T';
+ if (cached_status.kind != TARGET_WAITKIND_IGNORE)
+ {
+ /* The core always does a wait after creating the inferior, and
+ do_initial_child_stuff already ran the inferior to the
+ initial breakpoint (or an exit, if creating the process
+ fails). Report it now. */
+ *ourstatus = cached_status;
+ cached_status.kind = TARGET_WAITKIND_IGNORE;
+ return debug_event_ptid (¤t_event);
+ }
while (1)
{
- get_child_debug_event (&our_status);
+ if (!get_child_debug_event (ourstatus))
+ continue;
- if (our_status.kind == TARGET_WAITKIND_EXITED)
+ switch (ourstatus->kind)
{
+ case TARGET_WAITKIND_EXITED:
OUTMSG2 (("Child exited with retcode = %x\n",
- our_status.value.integer));
-
- *status = 'W';
-
- child_fetch_inferior_registers (-1);
-
- return our_status.value.integer;
- }
- else if (our_status.kind == TARGET_WAITKIND_STOPPED)
- {
- OUTMSG2 (("Child Stopped with signal = %x \n",
- WSTOPSIG (our_status.value.sig)));
-
- *status = 'T';
-
- child_fetch_inferior_registers (-1);
-
- return our_status.value.sig;
+ ourstatus->value.integer));
+ win32_clear_inferiors ();
+ return pid_to_ptid (current_event.dwProcessId);
+ case TARGET_WAITKIND_STOPPED:
+ case TARGET_WAITKIND_LOADED:
+ OUTMSG2 (("Child Stopped with signal = %d \n",
+ ourstatus->value.sig));
+
+ regcache = get_thread_regcache (current_thread, 1);
+ child_fetch_inferior_registers (regcache, -1);
+ return debug_event_ptid (¤t_event);
+ default:
+ OUTMSG (("Ignoring unknown internal event, %d\n", ourstatus->kind));
+ /* fall-through */
+ case TARGET_WAITKIND_SPURIOUS:
+ case TARGET_WAITKIND_EXECD:
+ /* do nothing, just continue */
+ child_continue (DBG_CONTINUE, -1);
+ break;
}
- else
- OUTMSG (("Ignoring unknown internal event, %d\n", our_status.kind));
-
- {
- struct thread_resume resume;
- resume.thread = -1;
- resume.step = 0;
- resume.sig = 0;
- resume.leave_stopped = 0;
- win32_resume (&resume);
- }
}
}
/* Fetch registers from the inferior process.
If REGNO is -1, fetch all registers; otherwise, fetch at least REGNO. */
static void
-win32_fetch_inferior_registers (int regno)
+win32_fetch_inferior_registers (struct regcache *regcache, int regno)
{
- child_fetch_inferior_registers (regno);
+ child_fetch_inferior_registers (regcache, regno);
}
/* Store registers to the inferior process.
If REGNO is -1, store all registers; otherwise, store at least REGNO. */
static void
-win32_store_inferior_registers (int regno)
+win32_store_inferior_registers (struct regcache *regcache, int regno)
{
- child_store_inferior_registers (regno);
+ child_store_inferior_registers (regcache, regno);
}
/* Read memory from the inferior process. This should generally be
@@ -1082,7 +1662,7 @@ win32_store_inferior_registers (int regno)
static int
win32_read_inferior_memory (CORE_ADDR memaddr, unsigned char *myaddr, int len)
{
- return child_xfer_memory (memaddr, myaddr, len, 0, 0) != len;
+ return child_xfer_memory (memaddr, (char *) myaddr, len, 0, 0) != len;
}
/* Write memory to the inferior process. This should generally be
@@ -1096,34 +1676,200 @@ win32_write_inferior_memory (CORE_ADDR memaddr, const unsigned char *myaddr,
return child_xfer_memory (memaddr, (char *) myaddr, len, 1, 0) != len;
}
-static const char *
-win32_arch_string (void)
+/* Send an interrupt request to the inferior process. */
+static void
+win32_request_interrupt (void)
{
- return "i386";
+ winapi_DebugBreakProcess DebugBreakProcess;
+ winapi_GenerateConsoleCtrlEvent GenerateConsoleCtrlEvent;
+
+#ifdef _WIN32_WCE
+ HMODULE dll = GetModuleHandle (_T("COREDLL.DLL"));
+#else
+ HMODULE dll = GetModuleHandle (_T("KERNEL32.DLL"));
+#endif
+
+ GenerateConsoleCtrlEvent = GETPROCADDRESS (dll, GenerateConsoleCtrlEvent);
+
+ if (GenerateConsoleCtrlEvent != NULL
+ && GenerateConsoleCtrlEvent (CTRL_BREAK_EVENT, current_process_id))
+ return;
+
+ /* GenerateConsoleCtrlEvent can fail if process id being debugged is
+ not a process group id.
+ Fallback to XP/Vista 'DebugBreakProcess', which generates a
+ breakpoint exception in the interior process. */
+
+ DebugBreakProcess = GETPROCADDRESS (dll, DebugBreakProcess);
+
+ if (DebugBreakProcess != NULL
+ && DebugBreakProcess (current_process_handle))
+ return;
+
+ /* Last resort, suspend all threads manually. */
+ soft_interrupt_requested = 1;
+}
+
+#ifdef _WIN32_WCE
+int
+win32_error_to_fileio_error (DWORD err)
+{
+ switch (err)
+ {
+ case ERROR_BAD_PATHNAME:
+ case ERROR_FILE_NOT_FOUND:
+ case ERROR_INVALID_NAME:
+ case ERROR_PATH_NOT_FOUND:
+ return FILEIO_ENOENT;
+ case ERROR_CRC:
+ case ERROR_IO_DEVICE:
+ case ERROR_OPEN_FAILED:
+ return FILEIO_EIO;
+ case ERROR_INVALID_HANDLE:
+ return FILEIO_EBADF;
+ case ERROR_ACCESS_DENIED:
+ case ERROR_SHARING_VIOLATION:
+ return FILEIO_EACCES;
+ case ERROR_NOACCESS:
+ return FILEIO_EFAULT;
+ case ERROR_BUSY:
+ return FILEIO_EBUSY;
+ case ERROR_ALREADY_EXISTS:
+ case ERROR_FILE_EXISTS:
+ return FILEIO_EEXIST;
+ case ERROR_BAD_DEVICE:
+ return FILEIO_ENODEV;
+ case ERROR_DIRECTORY:
+ return FILEIO_ENOTDIR;
+ case ERROR_FILENAME_EXCED_RANGE:
+ case ERROR_INVALID_DATA:
+ case ERROR_INVALID_PARAMETER:
+ case ERROR_NEGATIVE_SEEK:
+ return FILEIO_EINVAL;
+ case ERROR_TOO_MANY_OPEN_FILES:
+ return FILEIO_EMFILE;
+ case ERROR_HANDLE_DISK_FULL:
+ case ERROR_DISK_FULL:
+ return FILEIO_ENOSPC;
+ case ERROR_WRITE_PROTECT:
+ return FILEIO_EROFS;
+ case ERROR_NOT_SUPPORTED:
+ return FILEIO_ENOSYS;
+ }
+
+ return FILEIO_EUNKNOWN;
+}
+
+static void
+wince_hostio_last_error (char *buf)
+{
+ DWORD winerr = GetLastError ();
+ int fileio_err = win32_error_to_fileio_error (winerr);
+ sprintf (buf, "F-1,%x", fileio_err);
+}
+#endif
+
+/* Write Windows OS Thread Information Block address. */
+
+static int
+win32_get_tib_address (ptid_t ptid, CORE_ADDR *addr)
+{
+ win32_thread_info *th;
+ th = thread_rec (ptid, 0);
+ if (th == NULL)
+ return 0;
+ if (addr != NULL)
+ *addr = th->thread_local_base;
+ return 1;
+}
+
+/* Implementation of the target_ops method "sw_breakpoint_from_kind". */
+
+static const gdb_byte *
+win32_sw_breakpoint_from_kind (int kind, int *size)
+{
+ *size = the_low_target.breakpoint_len;
+ return the_low_target.breakpoint;
}
static struct target_ops win32_target_ops = {
win32_create_inferior,
+ NULL, /* post_create_inferior */
win32_attach,
win32_kill,
win32_detach,
+ win32_mourn,
+ win32_join,
win32_thread_alive,
win32_resume,
win32_wait,
win32_fetch_inferior_registers,
win32_store_inferior_registers,
+ NULL, /* prepare_to_access_memory */
+ NULL, /* done_accessing_memory */
win32_read_inferior_memory,
win32_write_inferior_memory,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- win32_arch_string
+ NULL, /* lookup_symbols */
+ win32_request_interrupt,
+ NULL, /* read_auxv */
+ win32_supports_z_point_type,
+ win32_insert_point,
+ win32_remove_point,
+ NULL, /* stopped_by_sw_breakpoint */
+ NULL, /* supports_stopped_by_sw_breakpoint */
+ NULL, /* stopped_by_hw_breakpoint */
+ NULL, /* supports_stopped_by_hw_breakpoint */
+ target_can_do_hardware_single_step,
+ win32_stopped_by_watchpoint,
+ win32_stopped_data_address,
+ NULL, /* read_offsets */
+ NULL, /* get_tls_address */
+ NULL, /* qxfer_spu */
+#ifdef _WIN32_WCE
+ wince_hostio_last_error,
+#else
+ hostio_last_error_from_errno,
+#endif
+ NULL, /* qxfer_osdata */
+ NULL, /* qxfer_siginfo */
+ NULL, /* supports_non_stop */
+ NULL, /* async */
+ NULL, /* start_non_stop */
+ NULL, /* supports_multi_process */
+ NULL, /* supports_fork_events */
+ NULL, /* supports_vfork_events */
+ NULL, /* supports_exec_events */
+ NULL, /* handle_new_gdb_connection */
+ NULL, /* handle_monitor_command */
+ NULL, /* core_of_thread */
+ NULL, /* read_loadmap */
+ NULL, /* process_qsupported */
+ NULL, /* supports_tracepoints */
+ NULL, /* read_pc */
+ NULL, /* write_pc */
+ NULL, /* thread_stopped */
+ win32_get_tib_address,
+ NULL, /* pause_all */
+ NULL, /* unpause_all */
+ NULL, /* stabilize_threads */
+ NULL, /* install_fast_tracepoint_jump_pad */
+ NULL, /* emit_ops */
+ NULL, /* supports_disable_randomization */
+ NULL, /* get_min_fast_tracepoint_insn_len */
+ NULL, /* qxfer_libraries_svr4 */
+ NULL, /* support_agent */
+ NULL, /* support_btrace */
+ NULL, /* enable_btrace */
+ NULL, /* disable_btrace */
+ NULL, /* read_btrace */
+ NULL, /* read_btrace_conf */
+ NULL, /* supports_range_stepping */
+ NULL, /* pid_to_exec_file */
+ NULL, /* multifs_open */
+ NULL, /* multifs_unlink */
+ NULL, /* multifs_readlink */
+ NULL, /* breakpoint_kind_from_pc */
+ win32_sw_breakpoint_from_kind,
};
/* Initialize the Win32 backend. */
@@ -1131,6 +1877,5 @@ void
initialize_low (void)
{
set_target_ops (&win32_target_ops);
-
- init_registers ();
+ the_low_target.arch_setup ();
}