#include "gdbsupport/common-inferior.h"
#include "gdbsupport/gdb_wait.h"
+using namespace windows_nat;
+
#ifndef USE_WIN32API
#include <sys/cygwin.h>
#endif
/* Globals. */
static int attaching = 0;
-static HANDLE current_process_handle = NULL;
-static DWORD current_process_id = 0;
-static DWORD main_thread_id = 0;
-static EXCEPTION_RECORD siginfo_er; /* Contents of $_siginfo */
-static enum gdb_signal last_sig = GDB_SIGNAL_0;
-
-/* The current debug event from WaitForDebugEvent. */
-static DEBUG_EVENT current_event;
/* A status that hasn't been reported to the core yet, and so
win32_wait should return it next, instead of fetching the next
by suspending all the threads. */
static int faked_breakpoint = 0;
+#ifdef __x86_64__
+bool wow64_process = false;
+#endif
+
const struct target_desc *win32_tdesc;
+#ifdef __x86_64__
+const struct target_desc *wow64_win32_tdesc;
+#endif
-#define NUM_REGS (the_low_target.num_regs)
+#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);
+#ifdef __x86_64__
+typedef BOOL (WINAPI *winapi_Wow64SetThreadContext) (HANDLE,
+ const WOW64_CONTEXT *);
+
+winapi_Wow64GetThreadContext win32_Wow64GetThreadContext;
+static winapi_Wow64SetThreadContext win32_Wow64SetThreadContext;
+#endif
+
#ifndef _WIN32_WCE
static void win32_add_all_dlls (void);
#endif
/* Get the thread context of the thread associated with TH. */
static void
-win32_get_thread_context (win32_thread_info *th)
+win32_get_thread_context (windows_thread_info *th)
{
- memset (&th->context, 0, sizeof (CONTEXT));
+#ifdef __x86_64__
+ if (wow64_process)
+ memset (&th->wow64_context, 0, sizeof (WOW64_CONTEXT));
+ else
+#endif
+ memset (&th->context, 0, sizeof (CONTEXT));
(*the_low_target.get_thread_context) (th);
#ifdef _WIN32_WCE
memcpy (&th->base_context, &th->context, sizeof (CONTEXT));
/* Set the thread context of the thread associated with TH. */
static void
-win32_set_thread_context (win32_thread_info *th)
+win32_set_thread_context (windows_thread_info *th)
{
#ifdef _WIN32_WCE
/* Calling SuspendThread on a thread that is running kernel code
it between stopping and resuming. */
if (memcmp (&th->context, &th->base_context, sizeof (CONTEXT)) != 0)
#endif
- SetThreadContext (th->h, &th->context);
+ {
+#ifdef __x86_64__
+ if (wow64_process)
+ win32_Wow64SetThreadContext (th->h, &th->wow64_context);
+ else
+#endif
+ SetThreadContext (th->h, &th->context);
+ }
}
/* Set the thread context of the thread associated with TH. */
static void
-win32_prepare_to_resume (win32_thread_info *th)
+win32_prepare_to_resume (windows_thread_info *th)
{
if (the_low_target.prepare_to_resume != NULL)
(*the_low_target.prepare_to_resume) (th);
/* See win32-low.h. */
void
-win32_require_context (win32_thread_info *th)
+win32_require_context (windows_thread_info *th)
{
- if (th->context.ContextFlags == 0)
+ DWORD context_flags;
+#ifdef __x86_64__
+ if (wow64_process)
+ context_flags = th->wow64_context.ContextFlags;
+ else
+#endif
+ context_flags = th->context.ContextFlags;
+ if (context_flags == 0)
{
- if (!th->suspended)
- {
- 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;
- }
-
+ th->suspend ();
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)
+/* See nat/windows-nat.h. */
+
+windows_thread_info *
+windows_nat::thread_rec (ptid_t ptid, thread_disposition_type disposition)
{
thread_info *thread = find_thread_ptid (ptid);
if (thread == NULL)
return NULL;
- win32_thread_info *th = (win32_thread_info *) thread_target_data (thread);
- if (get_context)
+ windows_thread_info *th = (windows_thread_info *) thread_target_data (thread);
+ if (disposition != DONT_INVALIDATE_CONTEXT)
win32_require_context (th);
return th;
}
/* Add a thread to the thread list. */
-static win32_thread_info *
+static windows_thread_info *
child_add_thread (DWORD pid, DWORD tid, HANDLE h, void *tlb)
{
- win32_thread_info *th;
+ windows_thread_info *th;
ptid_t ptid = ptid_t (pid, tid, 0);
- if ((th = thread_rec (ptid, FALSE)))
+ if ((th = thread_rec (ptid, DONT_INVALIDATE_CONTEXT)))
return th;
- th = XCNEW (win32_thread_info);
- th->tid = tid;
- th->h = h;
- th->thread_local_base = (CORE_ADDR) (uintptr_t) tlb;
+ CORE_ADDR base = (CORE_ADDR) (uintptr_t) tlb;
+#ifdef __x86_64__
+ /* For WOW64 processes, this is actually the pointer to the 64bit TIB,
+ and the 32bit TIB is exactly 2 pages after it. */
+ if (wow64_process)
+ base += 2 * 4096; /* page size = 4096 */
+#endif
+ th = new windows_thread_info (tid, h, base);
add_thread (ptid, th);
static void
delete_thread_info (thread_info *thread)
{
- win32_thread_info *th = (win32_thread_info *) thread_target_data (thread);
+ windows_thread_info *th = (windows_thread_info *) thread_target_data (thread);
remove_thread (thread);
- CloseHandle (th->h);
- free (th);
+ delete th;
}
/* Delete a thread from the list of threads. */
bool
win32_process_target::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));
+ return (z_type == Z_PACKET_SW_BP
+ || (the_low_target.supports_z_point_type != NULL
+ && the_low_target.supports_z_point_type (z_type)));
}
int
win32_process_target::insert_point (enum raw_bkpt_type type, CORE_ADDR addr,
int size, raw_breakpoint *bp)
{
- if (the_low_target.insert_point != NULL)
+ if (type == raw_bkpt_type_sw)
+ return insert_memory_breakpoint (bp);
+ else if (the_low_target.insert_point != NULL)
return the_low_target.insert_point (type, addr, size, bp);
else
/* Unsupported (see target.h). */
win32_process_target::remove_point (enum raw_bkpt_type type, CORE_ADDR addr,
int size, raw_breakpoint *bp)
{
- if (the_low_target.remove_point != NULL)
+ if (type == raw_bkpt_type_sw)
+ return remove_memory_breakpoint (bp);
+ else if (the_low_target.remove_point != NULL)
return the_low_target.remove_point (type, addr, size, bp);
else
/* Unsupported (see target.h). */
memset (¤t_event, 0, sizeof (current_event));
+#ifdef __x86_64__
+ BOOL wow64;
+ if (!IsWow64Process (proch, &wow64))
+ {
+ DWORD err = GetLastError ();
+ error ("Check if WOW64 process failed (error %d): %s\n",
+ (int) err, strwinerror (err));
+ }
+ wow64_process = wow64;
+
+ if (wow64_process
+ && (win32_Wow64GetThreadContext == nullptr
+ || win32_Wow64SetThreadContext == nullptr))
+ error ("WOW64 debugging is not supported on this system.\n");
+
+ ignore_first_breakpoint = !attached && wow64_process;
+#endif
+
proc = add_process (pid, attached);
- proc->tdesc = win32_tdesc;
+#ifdef __x86_64__
+ if (wow64_process)
+ proc->tdesc = wow64_win32_tdesc;
+ else
+#endif
+ proc->tdesc = win32_tdesc;
child_init_thread_list ();
child_initialization_done = 0;
{
struct target_waitstatus status;
- the_target->pt->wait (minus_one_ptid, &status, 0);
+ the_target->wait (minus_one_ptid, &status, 0);
/* Note win32_wait doesn't return thread events. */
if (status.kind != TARGET_WAITKIND_LOADED)
resume.kind = resume_continue;
resume.sig = 0;
- the_target->pt->resume (&resume, 1);
+ the_target->resume (&resume, 1);
}
}
static void
continue_one_thread (thread_info *thread, int thread_id)
{
- win32_thread_info *th = (win32_thread_info *) thread_target_data (thread);
+ windows_thread_info *th = (windows_thread_info *) thread_target_data (thread);
if (thread_id == -1 || thread_id == th->tid)
{
if (th->suspended)
{
- if (th->context.ContextFlags)
+ DWORD *context_flags;
+#ifdef __x86_64__
+ if (wow64_process)
+ context_flags = &th->wow64_context.ContextFlags;
+ else
+#endif
+ context_flags = &th->context.ContextFlags;
+ if (*context_flags)
{
win32_set_thread_context (th);
- th->context.ContextFlags = 0;
+ *context_flags = 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;
+ th->resume ();
}
}
}
static BOOL
child_continue (DWORD continue_status, int thread_id)
{
+ desired_stop_thread_id = thread_id;
+ if (matching_pending_stop (debug_threads))
+ return TRUE;
+
/* The inferior will only continue after the ContinueDebugEvent
call. */
for_each_thread ([&] (thread_info *thread)
});
faked_breakpoint = 0;
- if (!ContinueDebugEvent (current_event.dwProcessId,
- current_event.dwThreadId,
- continue_status))
- return FALSE;
-
- return TRUE;
+ return continue_last_debug_event (continue_status, debug_threads);
}
/* Fetch register(s) from the current thread context. */
child_fetch_inferior_registers (struct regcache *regcache, int r)
{
int regno;
- win32_thread_info *th = thread_rec (current_thread_ptid (), TRUE);
+ windows_thread_info *th = thread_rec (current_thread_ptid (),
+ INVALIDATE_CONTEXT);
if (r == -1 || r > NUM_REGS)
child_fetch_inferior_registers (regcache, NUM_REGS);
else
child_store_inferior_registers (struct regcache *regcache, int r)
{
int regno;
- win32_thread_info *th = thread_rec (current_thread_ptid (), TRUE);
+ windows_thread_info *th = thread_rec (current_thread_ptid (),
+ INVALIDATE_CONTEXT);
if (r == -1 || r == 0 || r > NUM_REGS)
child_store_inferior_registers (regcache, NUM_REGS);
else
(int) err, strwinerror (err));
}
-/* Handle OUTPUT_DEBUG_STRING_EVENT from child process. */
-static void
-handle_output_debug_string (void)
+/* See nat/windows-nat.h. */
+
+int
+windows_nat::handle_output_debug_string (struct target_waitstatus *ourstatus)
{
#define READ_BUFFER_LEN 1024
CORE_ADDR addr;
DWORD nbytes = current_event.u.DebugString.nDebugStringLength;
if (nbytes == 0)
- return;
+ return 0;
if (nbytes > READ_BUFFER_LEN)
nbytes = READ_BUFFER_LEN;
in Unicode. */
WCHAR buffer[(READ_BUFFER_LEN + 1) / sizeof (WCHAR)] = { 0 };
if (read_inferior_memory (addr, (unsigned char *) buffer, nbytes) != 0)
- return;
+ return 0;
wcstombs (s, buffer, (nbytes + 1) / sizeof (WCHAR));
}
else
{
if (read_inferior_memory (addr, (unsigned char *) s, nbytes) != 0)
- return;
+ return 0;
}
if (!startswith (s, "cYg"))
if (!server_waiting)
{
OUTMSG2(("%s", s));
- return;
+ return 0;
}
monitor_output (s);
}
#undef READ_BUFFER_LEN
+
+ return 0;
}
static void
{
if (!child_continue (DBG_CONTINUE, -1))
break;
- if (!WaitForDebugEvent (¤t_event, INFINITE))
+ if (!wait_for_debug_event (¤t_event, INFINITE))
break;
if (current_event.dwDebugEventCode == EXIT_PROCESS_DEBUG_EVENT)
break;
else if (current_event.dwDebugEventCode == OUTPUT_DEBUG_STRING_EVENT)
- handle_output_debug_string ();
+ handle_output_debug_string (nullptr);
}
win32_clear_inferiors ();
DWORD tid;
enum gdb_signal sig;
int step;
- win32_thread_info *th;
+ windows_thread_info *th;
DWORD continue_status = DBG_CONTINUE;
ptid_t ptid;
/* Get context for the currently selected thread. */
ptid = debug_event_ptid (¤t_event);
- th = thread_rec (ptid, FALSE);
+ th = thread_rec (ptid, DONT_INVALIDATE_CONTEXT);
if (th)
{
win32_prepare_to_resume (th);
- if (th->context.ContextFlags)
+ DWORD *context_flags;
+#ifdef __x86_64__
+ if (wow64_process)
+ context_flags = &th->wow64_context.ContextFlags;
+ else
+#endif
+ context_flags = &th->context.ContextFlags;
+ if (*context_flags)
{
/* Move register values from the inferior into the thread
context structure. */
}
win32_set_thread_context (th);
- th->context.ContextFlags = 0;
+ *context_flags = 0;
}
}
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);
+#ifdef __x86_64__
+typedef BOOL (WINAPI *winapi_EnumProcessModulesEx) (HANDLE, HMODULE *, DWORD,
+ LPDWORD, DWORD);
+#endif
typedef BOOL (WINAPI *winapi_GetModuleInformation) (HANDLE, HMODULE,
LPMODULEINFO, DWORD);
typedef DWORD (WINAPI *winapi_GetModuleFileNameExA) (HANDLE, HMODULE,
LPSTR, DWORD);
static winapi_EnumProcessModules win32_EnumProcessModules;
+#ifdef __x86_64__
+static winapi_EnumProcessModulesEx win32_EnumProcessModulesEx;
+#endif
static winapi_GetModuleInformation win32_GetModuleInformation;
static winapi_GetModuleFileNameExA win32_GetModuleFileNameExA;
return FALSE;
win32_EnumProcessModules =
GETPROCADDRESS (dll, EnumProcessModules);
+#ifdef __x86_64__
+ win32_EnumProcessModulesEx =
+ GETPROCADDRESS (dll, EnumProcessModulesEx);
+#endif
win32_GetModuleInformation =
GETPROCADDRESS (dll, GetModuleInformation);
win32_GetModuleFileNameExA =
GETPROCADDRESS (dll, GetModuleFileNameExA);
}
+#ifdef __x86_64__
+ if (wow64_process && win32_EnumProcessModulesEx == nullptr)
+ return FALSE;
+#endif
+
return (win32_EnumProcessModules != NULL
&& win32_GetModuleInformation != NULL
&& win32_GetModuleFileNameExA != NULL);
return;
cbNeeded = 0;
- ok = (*win32_EnumProcessModules) (current_process_handle,
- DllHandle,
- sizeof (HMODULE),
- &cbNeeded);
+#ifdef __x86_64__
+ if (wow64_process)
+ ok = (*win32_EnumProcessModulesEx) (current_process_handle,
+ DllHandle,
+ sizeof (HMODULE),
+ &cbNeeded,
+ LIST_MODULES_32BIT);
+ else
+#endif
+ ok = (*win32_EnumProcessModules) (current_process_handle,
+ DllHandle,
+ sizeof (HMODULE),
+ &cbNeeded);
if (!ok || !cbNeeded)
return;
if (!DllHandle)
return;
- ok = (*win32_EnumProcessModules) (current_process_handle,
- DllHandle,
- cbNeeded,
- &cbNeeded);
+#ifdef __x86_64__
+ if (wow64_process)
+ ok = (*win32_EnumProcessModulesEx) (current_process_handle,
+ DllHandle,
+ cbNeeded,
+ &cbNeeded,
+ LIST_MODULES_32BIT);
+ else
+#endif
+ ok = (*win32_EnumProcessModules) (current_process_handle,
+ DllHandle,
+ cbNeeded,
+ &cbNeeded);
if (!ok)
return;
+ char system_dir[MAX_PATH];
+ char syswow_dir[MAX_PATH];
+ size_t system_dir_len = 0;
+ bool convert_syswow_dir = false;
+#ifdef __x86_64__
+ if (wow64_process)
+#endif
+ {
+ /* This fails on 32bit Windows because it has no SysWOW64 directory,
+ and in this case a path conversion isn't necessary. */
+ UINT len = GetSystemWow64DirectoryA (syswow_dir, sizeof (syswow_dir));
+ if (len > 0)
+ {
+ /* Check that we have passed a large enough buffer. */
+ gdb_assert (len < sizeof (syswow_dir));
+
+ len = GetSystemDirectoryA (system_dir, sizeof (system_dir));
+ /* Error check. */
+ gdb_assert (len != 0);
+ /* Check that we have passed a large enough buffer. */
+ gdb_assert (len < sizeof (system_dir));
+
+ strcat (system_dir, "\\");
+ strcat (syswow_dir, "\\");
+ system_dir_len = strlen (system_dir);
+
+ convert_syswow_dir = true;
+ }
+
+ }
+
for (i = 1; i < ((size_t) cbNeeded / sizeof (HMODULE)); i++)
{
MODULEINFO mi;
dll_name,
MAX_PATH) == 0)
continue;
- win32_add_one_solib (dll_name, (CORE_ADDR) (uintptr_t) mi.lpBaseOfDll);
+
+ const char *name = dll_name;
+ /* Convert the DLL path of 32bit processes returned by
+ GetModuleFileNameEx from the 64bit system directory to the
+ 32bit syswow64 directory if necessary. */
+ std::string syswow_dll_path;
+ if (convert_syswow_dir
+ && strncasecmp (dll_name, system_dir, system_dir_len) == 0
+ && strchr (dll_name + system_dir_len, '\\') == nullptr)
+ {
+ syswow_dll_path = syswow_dir;
+ syswow_dll_path += dll_name + system_dir_len;
+ name = syswow_dll_path.c_str();
+ }
+
+ win32_add_one_solib (name, (CORE_ADDR) (uintptr_t) mi.lpBaseOfDll);
}
}
#endif
typedef BOOL (WINAPI *winapi_Module32First) (HANDLE, LPMODULEENTRY32);
typedef BOOL (WINAPI *winapi_Module32Next) (HANDLE, LPMODULEENTRY32);
-/* Handle a DLL load event.
+/* See nat/windows-nat.h. */
- 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)
+void
+windows_nat::handle_load_dll ()
{
LOAD_DLL_DEBUG_INFO *event = ¤t_event.u.LoadDll;
- char *dll_name;
+ const char *dll_name;
dll_name = get_image_name (current_process_handle,
event->lpImageName, event->fUnicode);
win32_add_one_solib (dll_name, (CORE_ADDR) (uintptr_t) event->lpBaseOfDll);
}
-/* Handle a DLL unload event.
+/* See nat/windows-nat.h. */
- 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)
+void
+windows_nat::handle_unload_dll ()
{
CORE_ADDR load_addr =
(CORE_ADDR) (uintptr_t) current_event.u.UnloadDll.lpBaseOfDll;
unloaded_dll (NULL, load_addr);
}
-static void
-handle_exception (struct target_waitstatus *ourstatus)
-{
- DWORD code = current_event.u.Exception.ExceptionRecord.ExceptionCode;
-
- memcpy (&siginfo_er, ¤t_event.u.Exception.ExceptionRecord,
- sizeof siginfo_er);
-
- ourstatus->kind = TARGET_WAITKIND_STOPPED;
-
- switch (code)
- {
- case EXCEPTION_ACCESS_VIOLATION:
- OUTMSG2 (("EXCEPTION_ACCESS_VIOLATION"));
- ourstatus->value.sig = GDB_SIGNAL_SEGV;
- break;
- case STATUS_STACK_OVERFLOW:
- OUTMSG2 (("STATUS_STACK_OVERFLOW"));
- ourstatus->value.sig = GDB_SIGNAL_SEGV;
- break;
- case STATUS_FLOAT_DENORMAL_OPERAND:
- OUTMSG2 (("STATUS_FLOAT_DENORMAL_OPERAND"));
- ourstatus->value.sig = GDB_SIGNAL_FPE;
- break;
- case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
- OUTMSG2 (("EXCEPTION_ARRAY_BOUNDS_EXCEEDED"));
- ourstatus->value.sig = GDB_SIGNAL_FPE;
- break;
- case STATUS_FLOAT_INEXACT_RESULT:
- OUTMSG2 (("STATUS_FLOAT_INEXACT_RESULT"));
- ourstatus->value.sig = GDB_SIGNAL_FPE;
- break;
- case STATUS_FLOAT_INVALID_OPERATION:
- OUTMSG2 (("STATUS_FLOAT_INVALID_OPERATION"));
- ourstatus->value.sig = GDB_SIGNAL_FPE;
- break;
- case STATUS_FLOAT_OVERFLOW:
- OUTMSG2 (("STATUS_FLOAT_OVERFLOW"));
- ourstatus->value.sig = GDB_SIGNAL_FPE;
- break;
- case STATUS_FLOAT_STACK_CHECK:
- OUTMSG2 (("STATUS_FLOAT_STACK_CHECK"));
- ourstatus->value.sig = GDB_SIGNAL_FPE;
- break;
- case STATUS_FLOAT_UNDERFLOW:
- OUTMSG2 (("STATUS_FLOAT_UNDERFLOW"));
- ourstatus->value.sig = GDB_SIGNAL_FPE;
- break;
- case STATUS_FLOAT_DIVIDE_BY_ZERO:
- OUTMSG2 (("STATUS_FLOAT_DIVIDE_BY_ZERO"));
- ourstatus->value.sig = GDB_SIGNAL_FPE;
- break;
- case STATUS_INTEGER_DIVIDE_BY_ZERO:
- OUTMSG2 (("STATUS_INTEGER_DIVIDE_BY_ZERO"));
- ourstatus->value.sig = GDB_SIGNAL_FPE;
- break;
- case STATUS_INTEGER_OVERFLOW:
- OUTMSG2 (("STATUS_INTEGER_OVERFLOW"));
- ourstatus->value.sig = GDB_SIGNAL_FPE;
- break;
- case EXCEPTION_BREAKPOINT:
- OUTMSG2 (("EXCEPTION_BREAKPOINT"));
- 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 = GDB_SIGNAL_INT;
- break;
- case DBG_CONTROL_BREAK:
- OUTMSG2 (("DBG_CONTROL_BREAK"));
- ourstatus->value.sig = GDB_SIGNAL_INT;
- break;
- case EXCEPTION_SINGLE_STEP:
- OUTMSG2 (("EXCEPTION_SINGLE_STEP"));
- ourstatus->value.sig = GDB_SIGNAL_TRAP;
- break;
- case EXCEPTION_ILLEGAL_INSTRUCTION:
- OUTMSG2 (("EXCEPTION_ILLEGAL_INSTRUCTION"));
- ourstatus->value.sig = GDB_SIGNAL_ILL;
- break;
- case EXCEPTION_PRIV_INSTRUCTION:
- OUTMSG2 (("EXCEPTION_PRIV_INSTRUCTION"));
- ourstatus->value.sig = GDB_SIGNAL_ILL;
- break;
- case EXCEPTION_NONCONTINUABLE_EXCEPTION:
- OUTMSG2 (("EXCEPTION_NONCONTINUABLE_EXCEPTION"));
- ourstatus->value.sig = GDB_SIGNAL_ILL;
- break;
- default:
- if (current_event.u.Exception.dwFirstChance)
- {
- 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 (thread_info *thread)
{
- win32_thread_info *th = (win32_thread_info *) thread_target_data (thread);
+ windows_thread_info *th = (windows_thread_info *) thread_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;
- }
+ th->suspend ();
}
static void
}
#endif
+/* See nat/windows-nat.h. */
+
+bool
+windows_nat::handle_ms_vc_exception (const EXCEPTION_RECORD *rec)
+{
+ return false;
+}
+
+/* See nat/windows-nat.h. */
+
+bool
+windows_nat::handle_access_violation (const EXCEPTION_RECORD *rec)
+{
+ return false;
+}
+
+/* A helper function that will, if needed, set
+ 'stopped_at_software_breakpoint' on the thread and adjust the
+ PC. */
+
+static void
+maybe_adjust_pc ()
+{
+ struct regcache *regcache = get_thread_regcache (current_thread, 1);
+ child_fetch_inferior_registers (regcache, -1);
+
+ windows_thread_info *th = thread_rec (current_thread_ptid (),
+ DONT_INVALIDATE_CONTEXT);
+ th->stopped_at_software_breakpoint = false;
+
+ if (current_event.dwDebugEventCode == EXCEPTION_DEBUG_EVENT
+ && ((current_event.u.Exception.ExceptionRecord.ExceptionCode
+ == EXCEPTION_BREAKPOINT)
+ || (current_event.u.Exception.ExceptionRecord.ExceptionCode
+ == STATUS_WX86_BREAKPOINT))
+ && child_initialization_done)
+ {
+ th->stopped_at_software_breakpoint = true;
+ CORE_ADDR pc = regcache_read_pc (regcache);
+ CORE_ADDR sw_breakpoint_pc = pc - the_low_target.decr_pc_after_break;
+ regcache_write_pc (regcache, sw_breakpoint_pc);
+ }
+}
+
/* Get the next event from the child. */
static int
-get_child_debug_event (struct target_waitstatus *ourstatus)
+get_child_debug_event (DWORD *continue_status,
+ struct target_waitstatus *ourstatus)
{
ptid_t ptid;
last_sig = GDB_SIGNAL_0;
ourstatus->kind = TARGET_WAITKIND_SPURIOUS;
+ *continue_status = DBG_CONTINUE;
/* Check if GDB sent us an interrupt request. */
check_remote_input_interrupt_request ();
happen is the user will see a spurious breakpoint. */
current_event.dwDebugEventCode = 0;
- if (!WaitForDebugEvent (¤t_event, 0))
+ if (!wait_for_debug_event (¤t_event, 0))
{
OUTMSG2(("no attach events left\n"));
fake_breakpoint_event ();
else
#endif
{
+ gdb::optional<pending_stop> stop = fetch_pending_stop (debug_threads);
+ if (stop.has_value ())
+ {
+ *ourstatus = stop->status;
+ current_event = stop->event;
+ ptid = debug_event_ptid (¤t_event);
+ current_thread = find_thread_ptid (ptid);
+ return 1;
+ }
+
/* Keep the wait time low enough for comfortable remote
interruption, but high enough so gdbserver doesn't become a
bottleneck. */
- if (!WaitForDebugEvent (¤t_event, 250))
+ if (!wait_for_debug_event (¤t_event, 250))
{
DWORD e = GetLastError();
ourstatus->value.sig = gdb_signal_from_host (exit_signal);
}
}
- child_continue (DBG_CONTINUE, -1);
+ child_continue (DBG_CONTINUE, desired_stop_thread_id);
CloseHandle (current_process_handle);
current_process_handle = NULL;
break;
"for pid=%u tid=%x\n",
(unsigned) current_event.dwProcessId,
(unsigned) current_event.dwThreadId));
- handle_exception (ourstatus);
+ if (handle_exception (ourstatus, debug_threads)
+ == HANDLE_EXCEPTION_UNHANDLED)
+ *continue_status = DBG_EXCEPTION_NOT_HANDLED;
break;
case OUTPUT_DEBUG_STRING_EVENT:
"for pid=%u tid=%x\n",
(unsigned) current_event.dwProcessId,
(unsigned) current_event.dwThreadId));
- handle_output_debug_string ();
+ handle_output_debug_string (nullptr);
break;
default:
}
ptid = debug_event_ptid (¤t_event);
- current_thread = find_thread_ptid (ptid);
+
+ if (desired_stop_thread_id != -1 && desired_stop_thread_id != ptid.lwp ())
+ {
+ /* Pending stop. See the comment by the definition of
+ "pending_stops" for details on why this is needed. */
+ OUTMSG2 (("get_windows_debug_event - "
+ "unexpected stop in 0x%lx (expecting 0x%x)\n",
+ ptid.lwp (), desired_stop_thread_id));
+ maybe_adjust_pc ();
+ pending_stops.push_back ({(DWORD) ptid.lwp (), *ourstatus, current_event});
+ ourstatus->kind = TARGET_WAITKIND_SPURIOUS;
+ }
+ else
+ current_thread = find_thread_ptid (ptid);
+
return 1;
}
win32_process_target::wait (ptid_t ptid, target_waitstatus *ourstatus,
int options)
{
- struct regcache *regcache;
-
if (cached_status.kind != TARGET_WAITKIND_IGNORE)
{
/* The core always does a wait after creating the inferior, and
while (1)
{
- if (!get_child_debug_event (ourstatus))
+ DWORD continue_status;
+ if (!get_child_debug_event (&continue_status, ourstatus))
continue;
switch (ourstatus->kind)
case TARGET_WAITKIND_STOPPED:
case TARGET_WAITKIND_SIGNALLED:
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);
+ {
+ OUTMSG2 (("Child Stopped with signal = %d \n",
+ ourstatus->value.sig));
+ maybe_adjust_pc ();
+ return debug_event_ptid (¤t_event);
+ }
default:
OUTMSG (("Ignoring unknown internal event, %d\n", ourstatus->kind));
/* fall-through */
case TARGET_WAITKIND_SPURIOUS:
/* do nothing, just continue */
- child_continue (DBG_CONTINUE, -1);
+ child_continue (continue_status, desired_stop_thread_id);
break;
}
}
if (readbuf == nullptr)
return -1;
- if (offset > sizeof (siginfo_er))
+ char *buf = (char *) &siginfo_er;
+ size_t bufsize = sizeof (siginfo_er);
+
+#ifdef __x86_64__
+ EXCEPTION_RECORD32 er32;
+ if (wow64_process)
+ {
+ buf = (char *) &er32;
+ bufsize = sizeof (er32);
+
+ er32.ExceptionCode = siginfo_er.ExceptionCode;
+ er32.ExceptionFlags = siginfo_er.ExceptionFlags;
+ er32.ExceptionRecord = (uintptr_t) siginfo_er.ExceptionRecord;
+ er32.ExceptionAddress = (uintptr_t) siginfo_er.ExceptionAddress;
+ er32.NumberParameters = siginfo_er.NumberParameters;
+ int i;
+ for (i = 0; i < EXCEPTION_MAXIMUM_PARAMETERS; i++)
+ er32.ExceptionInformation[i] = siginfo_er.ExceptionInformation[i];
+ }
+#endif
+
+ if (offset > bufsize)
return -1;
- if (offset + len > sizeof (siginfo_er))
- len = sizeof (siginfo_er) - offset;
+ if (offset + len > bufsize)
+ len = bufsize - offset;
- memcpy (readbuf, (char *) &siginfo_er + offset, len);
+ memcpy (readbuf, buf + offset, len);
return len;
}
int
win32_process_target::get_tib_address (ptid_t ptid, CORE_ADDR *addr)
{
- win32_thread_info *th;
- th = thread_rec (ptid, 0);
+ windows_thread_info *th;
+ th = thread_rec (ptid, DONT_INVALIDATE_CONTEXT);
if (th == NULL)
return 0;
if (addr != NULL)
return the_low_target.breakpoint;
}
+bool
+win32_process_target::stopped_by_sw_breakpoint ()
+{
+ windows_thread_info *th = thread_rec (current_thread_ptid (),
+ DONT_INVALIDATE_CONTEXT);
+ return th == nullptr ? false : th->stopped_at_software_breakpoint;
+}
+
+bool
+win32_process_target::supports_stopped_by_sw_breakpoint ()
+{
+ return true;
+}
+
+CORE_ADDR
+win32_process_target::read_pc (struct regcache *regcache)
+{
+ return (*the_low_target.get_pc) (regcache);
+}
+
+void
+win32_process_target::write_pc (struct regcache *regcache, CORE_ADDR pc)
+{
+ return (*the_low_target.set_pc) (regcache, pc);
+}
+
/* The win32 target ops object. */
static win32_process_target the_win32_target;
-static process_stratum_target win32_target_ops = {
- &the_win32_target,
-};
-
/* Initialize the Win32 backend. */
void
initialize_low (void)
{
- set_target_ops (&win32_target_ops);
+ set_target_ops (&the_win32_target);
the_low_target.arch_setup ();
+
+#ifdef __x86_64__
+ /* These functions are loaded dynamically, because they are not available
+ on Windows XP. */
+ HMODULE dll = GetModuleHandle (_T("KERNEL32.DLL"));
+ win32_Wow64GetThreadContext = GETPROCADDRESS (dll, Wow64GetThreadContext);
+ win32_Wow64SetThreadContext = GETPROCADDRESS (dll, Wow64SetThreadContext);
+#endif
}