/* Low level interface to Windows debugging, for gdbserver.
- Copyright (C) 2006-2021 Free Software Foundation, Inc.
+ Copyright (C) 2006-2023 Free Software Foundation, Inc.
Contributed by Leo Zayas. Based on "win32-nat.c" from GDB.
#include "server.h"
#include "regcache.h"
-#include "gdb/fileio.h"
+#include "gdbsupport/fileio.h"
#include "mem-break.h"
#include "win32-low.h"
#include "gdbthread.h"
using namespace windows_nat;
+/* See win32-low.h. */
+gdbserver_windows_process windows_process;
+
#ifndef USE_WIN32API
#include <sys/cygwin.h>
#endif
#define _T(x) TEXT (x)
#endif
-#ifndef COUNTOF
-#define COUNTOF(STR) (sizeof (STR) / sizeof ((STR)[0]))
-#endif
-
-#define GETPROCADDRESS(DLL, PROC) \
- ((winapi_ ## PROC) GetProcAddress (DLL, #PROC))
-
int using_threads = 1;
-/* Globals. */
-static int attaching = 0;
-
-/* 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;
-
-/* Non zero if an interrupt request is to be satisfied by suspending
- all threads. */
-static int soft_interrupt_requested = 0;
-
-/* Non zero if the inferior is stopped in a simulated breakpoint done
- by suspending all the threads. */
-static int faked_breakpoint = 0;
-
-/* True if current_process_handle needs to be closed. */
-static bool open_process_used = false;
-
const struct target_desc *win32_tdesc;
#ifdef __x86_64__
const struct target_desc *wow64_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);
-
-#ifdef __x86_64__
-typedef BOOL (WINAPI *winapi_Wow64SetThreadContext) (HANDLE,
- const WOW64_CONTEXT *);
-
-winapi_Wow64GetThreadContext win32_Wow64GetThreadContext;
-static winapi_Wow64SetThreadContext win32_Wow64SetThreadContext;
-#endif
-
-static void win32_add_all_dlls (void);
-
/* Get the thread ID from the current selected inferior (the current
thread). */
static ptid_t
win32_get_thread_context (windows_thread_info *th)
{
#ifdef __x86_64__
- if (wow64_process)
+ if (windows_process.wow64_process)
memset (&th->wow64_context, 0, sizeof (WOW64_CONTEXT));
else
#endif
win32_set_thread_context (windows_thread_info *th)
{
#ifdef __x86_64__
- if (wow64_process)
- win32_Wow64SetThreadContext (th->h, &th->wow64_context);
+ if (windows_process.wow64_process)
+ Wow64SetThreadContext (th->h, &th->wow64_context);
else
#endif
SetThreadContext (th->h, &th->context);
{
DWORD context_flags;
#ifdef __x86_64__
- if (wow64_process)
+ if (windows_process.wow64_process)
context_flags = th->wow64_context.ContextFlags;
else
#endif
/* See nat/windows-nat.h. */
windows_thread_info *
-windows_nat::thread_rec (ptid_t ptid, thread_disposition_type disposition)
+gdbserver_windows_process::thread_rec
+ (ptid_t ptid, thread_disposition_type disposition)
{
thread_info *thread = find_thread_ptid (ptid);
if (thread == NULL)
windows_thread_info *th;
ptid_t ptid = ptid_t (pid, tid, 0);
- if ((th = thread_rec (ptid, DONT_INVALIDATE_CONTEXT)))
+ if ((th = windows_process.thread_rec (ptid, DONT_INVALIDATE_CONTEXT)))
return th;
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)
+ if (windows_process.wow64_process)
base += 2 * 4096; /* page size = 4096 */
#endif
th = new windows_thread_info (tid, h, base);
if (write)
{
- success = WriteProcessMemory (current_process_handle, (LPVOID) addr,
+ success = WriteProcessMemory (windows_process.handle, (LPVOID) addr,
(LPCVOID) our, len, &done);
if (!success)
lasterror = GetLastError ();
- FlushInstructionCache (current_process_handle, (LPCVOID) addr, len);
+ FlushInstructionCache (windows_process.handle, (LPCVOID) addr, len);
}
else
{
- success = ReadProcessMemory (current_process_handle, (LPCVOID) addr,
+ success = ReadProcessMemory (windows_process.handle, (LPCVOID) addr,
(LPVOID) our, len, &done);
if (!success)
lasterror = GetLastError ();
for_each_thread (delete_thread_info);
}
-/* Zero during the child initialization phase, and nonzero otherwise. */
-
-static int child_initialization_done = 0;
-
static void
do_initial_child_stuff (HANDLE proch, DWORD pid, int attached)
{
struct process_info *proc;
- last_sig = GDB_SIGNAL_0;
-
- current_process_handle = proch;
- current_process_id = pid;
- main_thread_id = 0;
+ windows_process.last_sig = GDB_SIGNAL_0;
+ windows_process.handle = proch;
+ windows_process.main_thread_id = 0;
- soft_interrupt_requested = 0;
- faked_breakpoint = 0;
- open_process_used = true;
+ windows_process.soft_interrupt_requested = 0;
+ windows_process.faked_breakpoint = 0;
+ windows_process.open_process_used = true;
- memset (¤t_event, 0, sizeof (current_event));
+ memset (&windows_process.current_event, 0,
+ sizeof (windows_process.current_event));
#ifdef __x86_64__
BOOL wow64;
error ("Check if WOW64 process failed (error %d): %s\n",
(int) err, strwinerror (err));
}
- wow64_process = wow64;
+ windows_process.wow64_process = wow64;
- if (wow64_process
- && (win32_Wow64GetThreadContext == nullptr
- || win32_Wow64SetThreadContext == nullptr))
+ if (windows_process.wow64_process
+ && (Wow64GetThreadContext == nullptr
+ || Wow64SetThreadContext == nullptr))
error ("WOW64 debugging is not supported on this system.\n");
- ignore_first_breakpoint = !attached && wow64_process;
+ windows_process.ignore_first_breakpoint
+ = !attached && windows_process.wow64_process;
#endif
proc = add_process (pid, attached);
#ifdef __x86_64__
- if (wow64_process)
+ if (windows_process.wow64_process)
proc->tdesc = wow64_win32_tdesc;
else
#endif
proc->tdesc = win32_tdesc;
child_init_thread_list ();
- child_initialization_done = 0;
+ windows_process.child_initialization_done = 0;
if (the_low_target.initial_stuff != NULL)
(*the_low_target.initial_stuff) ();
- cached_status.kind = TARGET_WAITKIND_IGNORE;
+ windows_process.cached_status.set_ignore ();
/* Flush all currently pending debug events (thread and dll list) up
to the initial breakpoint. */
the_target->wait (minus_one_ptid, &status, 0);
/* Note win32_wait doesn't return thread events. */
- if (status.kind != TARGET_WAITKIND_LOADED)
+ if (status.kind () != TARGET_WAITKIND_LOADED)
{
- cached_status = status;
+ windows_process.cached_status = status;
break;
}
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 ();
+ windows_process.add_all_dlls ();
- child_initialization_done = 1;
+ windows_process.child_initialization_done = 1;
}
/* Resume all artificially suspended threads if we are continuing
{
DWORD *context_flags;
#ifdef __x86_64__
- if (wow64_process)
+ if (windows_process.wow64_process)
context_flags = &th->wow64_context.ContextFlags;
else
#endif
static BOOL
child_continue (DWORD continue_status, int thread_id)
{
- desired_stop_thread_id = thread_id;
- if (matching_pending_stop (debug_threads))
+ windows_process.desired_stop_thread_id = thread_id;
+ if (windows_process.matching_pending_stop (debug_threads))
return TRUE;
/* The inferior will only continue after the ContinueDebugEvent
{
continue_one_thread (thread, thread_id);
});
- faked_breakpoint = 0;
+ windows_process.faked_breakpoint = 0;
return continue_last_debug_event (continue_status, debug_threads);
}
child_fetch_inferior_registers (struct regcache *regcache, int r)
{
int regno;
- windows_thread_info *th = thread_rec (current_thread_ptid (),
- INVALIDATE_CONTEXT);
+ windows_thread_info *th
+ = windows_process.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;
- windows_thread_info *th = thread_rec (current_thread_ptid (),
- INVALIDATE_CONTEXT);
+ windows_thread_info *th
+ = windows_process.thread_rec (current_thread_ptid (),
+ INVALIDATE_CONTEXT);
if (r == -1 || r == 0 || r > NUM_REGS)
child_store_inferior_registers (regcache, NUM_REGS);
else
(*the_low_target.store_inferior_register) (regcache, th, regno);
}
-/* 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)
-{
- 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;
-}
-
static BOOL
create_process (const char *program, char *args,
DWORD flags, PROCESS_INFORMATION *pi)
{
- const char *inferior_cwd = get_inferior_cwd ();
+ const std::string &inferior_cwd = get_inferior_cwd ();
BOOL ret;
size_t argslen, proglen;
strcpy (program_and_args, program);
strcat (program_and_args, " ");
strcat (program_and_args, args);
- ret = CreateProcessA (program, /* image name */
+ ret = create_process (program, /* image name */
program_and_args, /* command line */
- NULL, /* security */
- NULL, /* thread */
- TRUE, /* inherit handles */
flags, /* start flags */
NULL, /* environment */
/* current directory */
- (inferior_cwd == NULL
+ (inferior_cwd.empty ()
? NULL
- : gdb_tilde_expand (inferior_cwd).c_str()),
+ : gdb_tilde_expand (inferior_cwd.c_str ()).c_str()),
+ get_client_state ().disable_randomization,
&si, /* start info */
pi); /* proc info */
char *args = (char *) str_program_args.c_str ();
/* win32_wait needs to know we're not attaching. */
- attaching = 0;
+ windows_process.attaching = 0;
if (!program)
error ("No executable specified, specify executable to debug.\n");
/* Wait till we are at 1st instruction in program, return new pid
(assuming success). */
- cs.last_ptid = wait (ptid_t (current_process_id), &cs.last_status, 0);
+ cs.last_ptid = wait (ptid_t (pi.dwProcessId), &cs.last_status, 0);
/* Necessary for handle_v_kill. */
- signal_pid = current_process_id;
+ signal_pid = pi.dwProcessId;
- return current_process_id;
+ return pi.dwProcessId;
}
/* Attach to a running process.
win32_process_target::attach (unsigned long pid)
{
HANDLE h;
- winapi_DebugSetProcessKillOnExit DebugSetProcessKillOnExit = NULL;
DWORD err;
- HMODULE dll = GetModuleHandle (_T("KERNEL32.DLL"));
- DebugSetProcessKillOnExit = GETPROCADDRESS (dll, DebugSetProcessKillOnExit);
h = OpenProcess (PROCESS_ALL_ACCESS, FALSE, pid);
if (h != NULL)
{
if (DebugActiveProcess (pid))
{
- if (DebugSetProcessKillOnExit != NULL)
- DebugSetProcessKillOnExit (FALSE);
+ DebugSetProcessKillOnExit (FALSE);
/* win32_wait needs to know we're attaching. */
- attaching = 1;
+ windows_process.attaching = 1;
do_initial_child_stuff (h, pid, 1);
return 0;
}
/* See nat/windows-nat.h. */
int
-windows_nat::handle_output_debug_string (struct target_waitstatus *ourstatus)
+gdbserver_windows_process::handle_output_debug_string
+ (struct target_waitstatus *ourstatus)
{
#define READ_BUFFER_LEN 1024
CORE_ADDR addr;
static void
win32_clear_inferiors (void)
{
- if (open_process_used)
+ if (windows_process.open_process_used)
{
- CloseHandle (current_process_handle);
- open_process_used = false;
+ CloseHandle (windows_process.handle);
+ windows_process.open_process_used = false;
}
for_each_thread (delete_thread_info);
- siginfo_er.ExceptionCode = 0;
+ windows_process.siginfo_er.ExceptionCode = 0;
clear_inferiors ();
}
int
win32_process_target::kill (process_info *process)
{
- TerminateProcess (current_process_handle, 0);
+ TerminateProcess (windows_process.handle, 0);
for (;;)
{
if (!child_continue (DBG_CONTINUE, -1))
break;
- if (!wait_for_debug_event (¤t_event, INFINITE))
+ if (!wait_for_debug_event (&windows_process.current_event, INFINITE))
break;
- if (current_event.dwDebugEventCode == EXIT_PROCESS_DEBUG_EVENT)
+ if (windows_process.current_event.dwDebugEventCode
+ == EXIT_PROCESS_DEBUG_EVENT)
break;
- else if (current_event.dwDebugEventCode == OUTPUT_DEBUG_STRING_EVENT)
- handle_output_debug_string (nullptr);
+ else if (windows_process.current_event.dwDebugEventCode
+ == OUTPUT_DEBUG_STRING_EVENT)
+ windows_process.handle_output_debug_string (nullptr);
}
win32_clear_inferiors ();
int
win32_process_target::detach (process_info *process)
{
- winapi_DebugActiveProcessStop DebugActiveProcessStop = NULL;
- winapi_DebugSetProcessKillOnExit DebugSetProcessKillOnExit = NULL;
- HMODULE dll = GetModuleHandle (_T("KERNEL32.DLL"));
- 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;
+ this->resume (&resume, 1);
- {
- struct thread_resume resume;
- resume.thread = minus_one_ptid;
- resume.kind = resume_continue;
- resume.sig = 0;
- this->resume (&resume, 1);
- }
-
- if (!DebugActiveProcessStop (current_process_id))
+ if (!DebugActiveProcessStop (process->pid))
return -1;
DebugSetProcessKillOnExit (FALSE);
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;
+ tid = windows_process.current_event.dwThreadId;
if (resume_info[0].thread != minus_one_ptid)
{
if (sig != GDB_SIGNAL_0)
{
- if (current_event.dwDebugEventCode != EXCEPTION_DEBUG_EVENT)
+ if (windows_process.current_event.dwDebugEventCode
+ != EXCEPTION_DEBUG_EVENT)
{
OUTMSG (("Cannot continue with signal %s here.\n",
gdb_signal_to_string (sig)));
}
- else if (sig == last_sig)
+ else if (sig == windows_process.last_sig)
continue_status = DBG_EXCEPTION_NOT_HANDLED;
else
OUTMSG (("Can only continue with received signal %s.\n",
- gdb_signal_to_string (last_sig)));
+ gdb_signal_to_string (windows_process.last_sig)));
}
- last_sig = GDB_SIGNAL_0;
+ windows_process.last_sig = GDB_SIGNAL_0;
/* Get context for the currently selected thread. */
- ptid = debug_event_ptid (¤t_event);
- th = thread_rec (ptid, DONT_INVALIDATE_CONTEXT);
+ ptid = debug_event_ptid (&windows_process.current_event);
+ th = windows_process.thread_rec (ptid, DONT_INVALIDATE_CONTEXT);
if (th)
{
win32_prepare_to_resume (th);
DWORD *context_flags;
#ifdef __x86_64__
- if (wow64_process)
+ if (windows_process.wow64_process)
context_flags = &th->wow64_context.ContextFlags;
else
#endif
child_continue (continue_status, tid);
}
-static void
-win32_add_one_solib (const char *name, CORE_ADDR load_addr)
+/* See nat/windows-nat.h. */
+
+void
+gdbserver_windows_process::handle_load_dll (const char *name, LPVOID base)
{
+ CORE_ADDR load_addr = (CORE_ADDR) (uintptr_t) base;
+
char buf[MAX_PATH + 1];
char buf2[MAX_PATH + 1];
loaded_dll (buf2, load_addr);
}
-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;
-
-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);
-#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);
-}
-
-/* Iterate over all DLLs currently mapped by our inferior, looking for
- a DLL loaded at LOAD_ADDR; if found, return its file name,
- otherwise return NULL. If LOAD_ADDR is NULL, add all mapped DLLs
- to our list of solibs. */
-
-static char *
-win32_add_dll (LPVOID load_addr)
-{
- size_t i;
- HMODULE dh_buf[1];
- HMODULE *DllHandle = dh_buf;
- DWORD cbNeeded;
- BOOL ok;
-
- if (!load_psapi ())
- return NULL;
-
- cbNeeded = 0;
-#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 NULL;
-
- DllHandle = (HMODULE *) alloca (cbNeeded);
- if (!DllHandle)
- return NULL;
-
-#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 NULL;
-
- 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;
- static 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;
-
- if (load_addr != nullptr && mi.lpBaseOfDll != load_addr)
- continue;
-
- 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();
- }
-
- if (load_addr != nullptr)
- {
- if (name != dll_name)
- strcpy (dll_name, name);
- return dll_name;
- }
- else
- win32_add_one_solib (name, (CORE_ADDR) (uintptr_t) mi.lpBaseOfDll);
- }
- return NULL;
-}
-
-/* Iterate over all DLLs currently mapped by our inferior, and
- add them to our list of solibs. */
-
-static void
-win32_add_all_dlls (void)
-{
- win32_add_dll (NULL);
-}
-
-typedef HANDLE (WINAPI *winapi_CreateToolhelp32Snapshot) (DWORD, DWORD);
-typedef BOOL (WINAPI *winapi_Module32First) (HANDLE, LPMODULEENTRY32);
-typedef BOOL (WINAPI *winapi_Module32Next) (HANDLE, LPMODULEENTRY32);
-
/* See nat/windows-nat.h. */
void
-windows_nat::handle_load_dll ()
-{
- LOAD_DLL_DEBUG_INFO *event = ¤t_event.u.LoadDll;
- const char *dll_name;
-
- dll_name = get_image_name (current_process_handle,
- event->lpImageName, event->fUnicode);
-#ifndef _WIN32_WCE
- if (dll_name == nullptr
- && event->lpBaseOfDll != nullptr)
- dll_name = win32_add_dll (event->lpBaseOfDll);
-#endif
- if (dll_name == nullptr)
- return;
-
- win32_add_one_solib (dll_name, (CORE_ADDR) (uintptr_t) event->lpBaseOfDll);
-}
-
-/* See nat/windows-nat.h. */
-
-void
-windows_nat::handle_unload_dll ()
+gdbserver_windows_process::handle_unload_dll ()
{
CORE_ADDR load_addr =
(CORE_ADDR) (uintptr_t) current_event.u.UnloadDll.lpBaseOfDll;
{
OUTMSG2(("fake_breakpoint_event\n"));
- faked_breakpoint = 1;
+ windows_process.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
+ memset (&windows_process.current_event, 0,
+ sizeof (windows_process.current_event));
+ windows_process.current_event.dwThreadId = windows_process.main_thread_id;
+ windows_process.current_event.dwDebugEventCode = EXCEPTION_DEBUG_EVENT;
+ windows_process.current_event.u.Exception.ExceptionRecord.ExceptionCode
= EXCEPTION_BREAKPOINT;
for_each_thread (suspend_one_thread);
/* 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)
+gdbserver_windows_process::handle_access_violation
+ (const EXCEPTION_RECORD *rec)
{
return false;
}
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);
+ windows_thread_info *th
+ = windows_process.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
+ if (windows_process.current_event.dwDebugEventCode == EXCEPTION_DEBUG_EVENT
+ && ((windows_process.current_event.u.Exception.ExceptionRecord.ExceptionCode
== EXCEPTION_BREAKPOINT)
- || (current_event.u.Exception.ExceptionRecord.ExceptionCode
+ || (windows_process.current_event.u.Exception.ExceptionRecord.ExceptionCode
== STATUS_WX86_BREAKPOINT))
- && child_initialization_done)
+ && windows_process.child_initialization_done)
{
th->stopped_at_software_breakpoint = true;
CORE_ADDR pc = regcache_read_pc (regcache);
{
ptid_t ptid;
- last_sig = GDB_SIGNAL_0;
- ourstatus->kind = TARGET_WAITKIND_SPURIOUS;
+ windows_process.last_sig = GDB_SIGNAL_0;
+ ourstatus->set_spurious ();
*continue_status = DBG_CONTINUE;
/* Check if GDB sent us an interrupt request. */
check_remote_input_interrupt_request ();
- if (soft_interrupt_requested)
+ DEBUG_EVENT *current_event = &windows_process.current_event;
+
+ if (windows_process.soft_interrupt_requested)
{
- soft_interrupt_requested = 0;
+ windows_process.soft_interrupt_requested = 0;
fake_breakpoint_event ();
goto gotevent;
}
- attaching = 0;
+ windows_process.attaching = 0;
{
- gdb::optional<pending_stop> stop = fetch_pending_stop (debug_threads);
+ gdb::optional<pending_stop> stop
+ = windows_process.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);
+ windows_process.current_event = stop->event;
+ ptid = debug_event_ptid (&windows_process.current_event);
+ switch_to_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 (!wait_for_debug_event (¤t_event, 250))
+ if (!wait_for_debug_event (&windows_process.current_event, 250))
{
DWORD e = GetLastError();
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;
+ ourstatus->set_exited (1);
return 1;
}
gotevent:
- switch (current_event.dwDebugEventCode)
+ switch (current_event->dwDebugEventCode)
{
case CREATE_THREAD_DEBUG_EVENT:
OUTMSG2 (("gdbserver: kernel event CREATE_THREAD_DEBUG_EVENT "
"for pid=%u tid=%x)\n",
- (unsigned) current_event.dwProcessId,
- (unsigned) current_event.dwThreadId));
+ (unsigned) current_event->dwProcessId,
+ (unsigned) current_event->dwThreadId));
/* Record the existence of this thread. */
- child_add_thread (current_event.dwProcessId,
- current_event.dwThreadId,
- current_event.u.CreateThread.hThread,
- current_event.u.CreateThread.lpThreadLocalBase);
+ 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=%u tid=%x\n",
- (unsigned) current_event.dwProcessId,
- (unsigned) current_event.dwThreadId));
- child_delete_thread (current_event.dwProcessId,
- current_event.dwThreadId);
+ (unsigned) current_event->dwProcessId,
+ (unsigned) current_event->dwThreadId));
+ child_delete_thread (current_event->dwProcessId,
+ current_event->dwThreadId);
- current_thread = get_first_thread ();
+ switch_to_thread (get_first_thread ());
return 1;
case CREATE_PROCESS_DEBUG_EVENT:
OUTMSG2 (("gdbserver: kernel event CREATE_PROCESS_DEBUG_EVENT "
"for pid=%u tid=%x\n",
- (unsigned) current_event.dwProcessId,
- (unsigned) current_event.dwThreadId));
- CloseHandle (current_event.u.CreateProcessInfo.hFile);
+ (unsigned) current_event->dwProcessId,
+ (unsigned) current_event->dwThreadId));
+ CloseHandle (current_event->u.CreateProcessInfo.hFile);
- if (open_process_used)
+ if (windows_process.open_process_used)
{
- CloseHandle (current_process_handle);
- open_process_used = false;
+ CloseHandle (windows_process.handle);
+ windows_process.open_process_used = false;
}
- current_process_handle = current_event.u.CreateProcessInfo.hProcess;
- main_thread_id = current_event.dwThreadId;
+ windows_process.handle = current_event->u.CreateProcessInfo.hProcess;
+ windows_process.main_thread_id = current_event->dwThreadId;
/* Add the main thread. */
- child_add_thread (current_event.dwProcessId,
- main_thread_id,
- current_event.u.CreateProcessInfo.hThread,
- current_event.u.CreateProcessInfo.lpThreadLocalBase);
+ child_add_thread (current_event->dwProcessId,
+ windows_process.main_thread_id,
+ current_event->u.CreateProcessInfo.hThread,
+ current_event->u.CreateProcessInfo.lpThreadLocalBase);
break;
case EXIT_PROCESS_DEBUG_EVENT:
OUTMSG2 (("gdbserver: kernel event EXIT_PROCESS_DEBUG_EVENT "
"for pid=%u tid=%x\n",
- (unsigned) current_event.dwProcessId,
- (unsigned) current_event.dwThreadId));
+ (unsigned) current_event->dwProcessId,
+ (unsigned) current_event->dwThreadId));
{
- DWORD exit_status = current_event.u.ExitProcess.dwExitCode;
+ DWORD exit_status = current_event->u.ExitProcess.dwExitCode;
/* If the exit status looks like a fatal exception, but we
don't recognize the exception's code, make the original
exit status value available, to avoid losing information. */
int exit_signal
= WIFSIGNALED (exit_status) ? WTERMSIG (exit_status) : -1;
if (exit_signal == -1)
- {
- ourstatus->kind = TARGET_WAITKIND_EXITED;
- ourstatus->value.integer = exit_status;
- }
+ ourstatus->set_exited (exit_status);
else
- {
- ourstatus->kind = TARGET_WAITKIND_SIGNALLED;
- ourstatus->value.sig = gdb_signal_from_host (exit_signal);
- }
+ ourstatus->set_signalled (gdb_signal_from_host (exit_signal));
}
- child_continue (DBG_CONTINUE, desired_stop_thread_id);
+ child_continue (DBG_CONTINUE, windows_process.desired_stop_thread_id);
break;
case LOAD_DLL_DEBUG_EVENT:
OUTMSG2 (("gdbserver: kernel event LOAD_DLL_DEBUG_EVENT "
"for pid=%u tid=%x\n",
- (unsigned) current_event.dwProcessId,
- (unsigned) current_event.dwThreadId));
- CloseHandle (current_event.u.LoadDll.hFile);
- if (! child_initialization_done)
+ (unsigned) current_event->dwProcessId,
+ (unsigned) current_event->dwThreadId));
+ CloseHandle (current_event->u.LoadDll.hFile);
+ if (! windows_process.child_initialization_done)
break;
- handle_load_dll ();
+ windows_process.dll_loaded_event ();
- ourstatus->kind = TARGET_WAITKIND_LOADED;
- ourstatus->value.sig = GDB_SIGNAL_TRAP;
+ ourstatus->set_loaded ();
break;
case UNLOAD_DLL_DEBUG_EVENT:
OUTMSG2 (("gdbserver: kernel event UNLOAD_DLL_DEBUG_EVENT "
"for pid=%u tid=%x\n",
- (unsigned) current_event.dwProcessId,
- (unsigned) current_event.dwThreadId));
- if (! child_initialization_done)
+ (unsigned) current_event->dwProcessId,
+ (unsigned) current_event->dwThreadId));
+ if (! windows_process.child_initialization_done)
break;
- handle_unload_dll ();
- ourstatus->kind = TARGET_WAITKIND_LOADED;
- ourstatus->value.sig = GDB_SIGNAL_TRAP;
+ windows_process.handle_unload_dll ();
+ ourstatus->set_loaded ();
break;
case EXCEPTION_DEBUG_EVENT:
OUTMSG2 (("gdbserver: kernel event EXCEPTION_DEBUG_EVENT "
"for pid=%u tid=%x\n",
- (unsigned) current_event.dwProcessId,
- (unsigned) current_event.dwThreadId));
- if (handle_exception (ourstatus, debug_threads)
+ (unsigned) current_event->dwProcessId,
+ (unsigned) current_event->dwThreadId));
+ if (windows_process.handle_exception (ourstatus, debug_threads)
== HANDLE_EXCEPTION_UNHANDLED)
*continue_status = DBG_EXCEPTION_NOT_HANDLED;
break;
/* A message from the kernel (or Cygwin). */
OUTMSG2 (("gdbserver: kernel event OUTPUT_DEBUG_STRING_EVENT "
"for pid=%u tid=%x\n",
- (unsigned) current_event.dwProcessId,
- (unsigned) current_event.dwThreadId));
- handle_output_debug_string (nullptr);
+ (unsigned) current_event->dwProcessId,
+ (unsigned) current_event->dwThreadId));
+ windows_process.handle_output_debug_string (nullptr);
break;
default:
OUTMSG2 (("gdbserver: kernel event unknown "
"for pid=%u tid=%x code=%x\n",
- (unsigned) current_event.dwProcessId,
- (unsigned) current_event.dwThreadId,
- (unsigned) current_event.dwDebugEventCode));
+ (unsigned) current_event->dwProcessId,
+ (unsigned) current_event->dwThreadId,
+ (unsigned) current_event->dwDebugEventCode));
break;
}
- ptid = debug_event_ptid (¤t_event);
+ ptid = debug_event_ptid (&windows_process.current_event);
- if (desired_stop_thread_id != -1 && desired_stop_thread_id != ptid.lwp ())
+ if (windows_process.desired_stop_thread_id != -1
+ && windows_process.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));
+ ptid.lwp (), windows_process.desired_stop_thread_id));
maybe_adjust_pc ();
- pending_stops.push_back ({(DWORD) ptid.lwp (), *ourstatus, current_event});
- ourstatus->kind = TARGET_WAITKIND_SPURIOUS;
+ windows_process.pending_stops.push_back
+ ({(DWORD) ptid.lwp (), *ourstatus, *current_event});
+ ourstatus->set_spurious ();
}
else
- current_thread = find_thread_ptid (ptid);
+ switch_to_thread (find_thread_ptid (ptid));
return 1;
}
win32_process_target::wait (ptid_t ptid, target_waitstatus *ourstatus,
target_wait_flags options)
{
- if (cached_status.kind != TARGET_WAITKIND_IGNORE)
+ if (windows_process.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);
+ *ourstatus = windows_process.cached_status;
+ windows_process.cached_status.set_ignore ();
+ return debug_event_ptid (&windows_process.current_event);
}
while (1)
if (!get_child_debug_event (&continue_status, ourstatus))
continue;
- switch (ourstatus->kind)
+ switch (ourstatus->kind ())
{
case TARGET_WAITKIND_EXITED:
OUTMSG2 (("Child exited with retcode = %x\n",
- ourstatus->value.integer));
+ ourstatus->exit_status ()));
win32_clear_inferiors ();
- return ptid_t (current_event.dwProcessId);
+ return ptid_t (windows_process.current_event.dwProcessId);
case TARGET_WAITKIND_STOPPED:
case TARGET_WAITKIND_SIGNALLED:
case TARGET_WAITKIND_LOADED:
{
OUTMSG2 (("Child Stopped with signal = %d \n",
- ourstatus->value.sig));
+ ourstatus->sig ()));
maybe_adjust_pc ();
- return debug_event_ptid (¤t_event);
+ return debug_event_ptid (&windows_process.current_event);
}
default:
- OUTMSG (("Ignoring unknown internal event, %d\n", ourstatus->kind));
+ OUTMSG (("Ignoring unknown internal event, %d\n",
+ ourstatus->kind ()));
/* fall-through */
case TARGET_WAITKIND_SPURIOUS:
/* do nothing, just continue */
- child_continue (continue_status, desired_stop_thread_id);
+ child_continue (continue_status,
+ windows_process.desired_stop_thread_id);
break;
}
}
void
win32_process_target::request_interrupt ()
{
- winapi_DebugBreakProcess DebugBreakProcess;
- winapi_GenerateConsoleCtrlEvent GenerateConsoleCtrlEvent;
-
- HMODULE dll = GetModuleHandle (_T("KERNEL32.DLL"));
-
- GenerateConsoleCtrlEvent = GETPROCADDRESS (dll, GenerateConsoleCtrlEvent);
-
- if (GenerateConsoleCtrlEvent != NULL
- && GenerateConsoleCtrlEvent (CTRL_BREAK_EVENT, current_process_id))
+ if (GenerateConsoleCtrlEvent (CTRL_BREAK_EVENT, signal_pid))
return;
/* GenerateConsoleCtrlEvent can fail if process id being debugged is
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))
+ if (DebugBreakProcess (windows_process.handle))
return;
/* Last resort, suspend all threads manually. */
- soft_interrupt_requested = 1;
+ windows_process.soft_interrupt_requested = 1;
}
bool
unsigned const char *writebuf,
CORE_ADDR offset, int len)
{
- if (siginfo_er.ExceptionCode == 0)
+ if (windows_process.siginfo_er.ExceptionCode == 0)
return -1;
if (readbuf == nullptr)
return -1;
- char *buf = (char *) &siginfo_er;
- size_t bufsize = sizeof (siginfo_er);
+ char *buf = (char *) &windows_process.siginfo_er;
+ size_t bufsize = sizeof (windows_process.siginfo_er);
#ifdef __x86_64__
EXCEPTION_RECORD32 er32;
- if (wow64_process)
+ if (windows_process.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;
+ er32.ExceptionCode = windows_process.siginfo_er.ExceptionCode;
+ er32.ExceptionFlags = windows_process.siginfo_er.ExceptionFlags;
+ er32.ExceptionRecord
+ = (uintptr_t) windows_process.siginfo_er.ExceptionRecord;
+ er32.ExceptionAddress
+ = (uintptr_t) windows_process.siginfo_er.ExceptionAddress;
+ er32.NumberParameters = windows_process.siginfo_er.NumberParameters;
int i;
for (i = 0; i < EXCEPTION_MAXIMUM_PARAMETERS; i++)
- er32.ExceptionInformation[i] = siginfo_er.ExceptionInformation[i];
+ er32.ExceptionInformation[i]
+ = windows_process.siginfo_er.ExceptionInformation[i];
}
#endif
win32_process_target::get_tib_address (ptid_t ptid, CORE_ADDR *addr)
{
windows_thread_info *th;
- th = thread_rec (ptid, DONT_INVALIDATE_CONTEXT);
+ th = windows_process.thread_rec (ptid, DONT_INVALIDATE_CONTEXT);
if (th == NULL)
return 0;
if (addr != NULL)
bool
win32_process_target::stopped_by_sw_breakpoint ()
{
- windows_thread_info *th = thread_rec (current_thread_ptid (),
- DONT_INVALIDATE_CONTEXT);
+ windows_thread_info *th
+ = windows_process.thread_rec (current_thread_ptid (),
+ DONT_INVALIDATE_CONTEXT);
return th == nullptr ? false : th->stopped_at_software_breakpoint;
}
return (*the_low_target.set_pc) (regcache, pc);
}
+const char *
+win32_process_target::thread_name (ptid_t thread)
+{
+ windows_thread_info *th
+ = windows_process.thread_rec (current_thread_ptid (),
+ DONT_INVALIDATE_CONTEXT);
+ return th->thread_name ();
+}
+
+const char *
+win32_process_target::pid_to_exec_file (int pid)
+{
+ return windows_process.pid_to_exec_file (pid);
+}
+
/* The win32 target ops object. */
static win32_process_target the_win32_target;
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
+ initialize_loadable ();
}