Remove some globals from nat/windows-nat.c

nat/windows-nat.c has a number of globals that it uses to communicate
with its clients (gdb and gdbserver).  However, if we ever want the
Windows ports to be multi-inferior, globals won't work.

This patch takes a step toward that by moving most nat/windows-nat.c
globals into a new struct windows_process_info.  Many functions are
converted to be methods on this object.

A couple of globals remain, as they are needed to truly be global due
to the way that the Windows debugging APIs work.

The clients still have a global for the current process.  That is,
this patch is a step toward the end goal, but doesn't implement the
goal itself.
This commit is contained in:
Tom Tromey 2022-03-31 13:41:02 -06:00
parent fc0b013e44
commit 0578e87f93
4 changed files with 472 additions and 420 deletions

View file

@ -23,12 +23,6 @@
namespace windows_nat namespace windows_nat
{ {
HANDLE current_process_handle;
DWORD current_process_id;
DWORD main_thread_id;
enum gdb_signal last_sig = GDB_SIGNAL_0;
DEBUG_EVENT current_event;
/* The most recent event from WaitForDebugEvent. Unlike /* The most recent event from WaitForDebugEvent. Unlike
current_event, this is guaranteed never to come from a pending current_event, this is guaranteed never to come from a pending
stop. This is important because only data from the most recent stop. This is important because only data from the most recent
@ -36,15 +30,6 @@ DEBUG_EVENT current_event;
ContinueDebugEvent. */ ContinueDebugEvent. */
static DEBUG_EVENT last_wait_event; static DEBUG_EVENT last_wait_event;
DWORD desired_stop_thread_id = -1;
std::vector<pending_stop> pending_stops;
EXCEPTION_RECORD siginfo_er;
#ifdef __x86_64__
bool wow64_process = false;
bool ignore_first_breakpoint = false;
#endif
AdjustTokenPrivileges_ftype *AdjustTokenPrivileges; AdjustTokenPrivileges_ftype *AdjustTokenPrivileges;
DebugActiveProcessStop_ftype *DebugActiveProcessStop; DebugActiveProcessStop_ftype *DebugActiveProcessStop;
DebugBreakProcess_ftype *DebugBreakProcess; DebugBreakProcess_ftype *DebugBreakProcess;
@ -180,7 +165,8 @@ get_image_name (HANDLE h, void *address, int unicode)
#define MS_VC_EXCEPTION 0x406d1388 #define MS_VC_EXCEPTION 0x406d1388
handle_exception_result handle_exception_result
handle_exception (struct target_waitstatus *ourstatus, bool debug_exceptions) windows_process_info::handle_exception (struct target_waitstatus *ourstatus,
bool debug_exceptions)
{ {
#define DEBUG_EXCEPTION_SIMPLE(x) if (debug_exceptions) \ #define DEBUG_EXCEPTION_SIMPLE(x) if (debug_exceptions) \
debug_printf ("gdb: Target exception %s at %s\n", x, \ debug_printf ("gdb: Target exception %s at %s\n", x, \
@ -335,15 +321,10 @@ handle_exception (struct target_waitstatus *ourstatus, bool debug_exceptions)
#undef DEBUG_EXCEPTION_SIMPLE #undef DEBUG_EXCEPTION_SIMPLE
} }
/* Iterate over all DLLs currently mapped by our inferior, looking for /* See nat/windows-nat.h. */
a DLL which is loaded at LOAD_ADDR. If found, add the DLL to our
list of solibs; otherwise do nothing. LOAD_ADDR NULL means add all
DLLs to the list of solibs; this is used when the inferior finishes
its initialization, and all the DLLs it statically depends on are
presumed loaded. */
static void void
windows_add_dll (LPVOID load_addr) windows_process_info::add_dll (LPVOID load_addr)
{ {
HMODULE dummy_hmodule; HMODULE dummy_hmodule;
DWORD cb_needed; DWORD cb_needed;
@ -353,7 +334,7 @@ windows_add_dll (LPVOID load_addr)
#ifdef __x86_64__ #ifdef __x86_64__
if (wow64_process) if (wow64_process)
{ {
if (EnumProcessModulesEx (current_process_handle, &dummy_hmodule, if (EnumProcessModulesEx (handle, &dummy_hmodule,
sizeof (HMODULE), &cb_needed, sizeof (HMODULE), &cb_needed,
LIST_MODULES_32BIT) == 0) LIST_MODULES_32BIT) == 0)
return; return;
@ -361,7 +342,7 @@ windows_add_dll (LPVOID load_addr)
else else
#endif #endif
{ {
if (EnumProcessModules (current_process_handle, &dummy_hmodule, if (EnumProcessModules (handle, &dummy_hmodule,
sizeof (HMODULE), &cb_needed) == 0) sizeof (HMODULE), &cb_needed) == 0)
return; return;
} }
@ -373,7 +354,7 @@ windows_add_dll (LPVOID load_addr)
#ifdef __x86_64__ #ifdef __x86_64__
if (wow64_process) if (wow64_process)
{ {
if (EnumProcessModulesEx (current_process_handle, hmodules, if (EnumProcessModulesEx (handle, hmodules,
cb_needed, &cb_needed, cb_needed, &cb_needed,
LIST_MODULES_32BIT) == 0) LIST_MODULES_32BIT) == 0)
return; return;
@ -381,7 +362,7 @@ windows_add_dll (LPVOID load_addr)
else else
#endif #endif
{ {
if (EnumProcessModules (current_process_handle, hmodules, if (EnumProcessModules (handle, hmodules,
cb_needed, &cb_needed) == 0) cb_needed, &cb_needed) == 0)
return; return;
} }
@ -426,11 +407,11 @@ windows_add_dll (LPVOID load_addr)
char dll_name[MAX_PATH]; char dll_name[MAX_PATH];
#endif #endif
const char *name; const char *name;
if (GetModuleInformation (current_process_handle, hmodules[i], if (GetModuleInformation (handle, hmodules[i],
&mi, sizeof (mi)) == 0) &mi, sizeof (mi)) == 0)
continue; continue;
if (GetModuleFileNameEx (current_process_handle, hmodules[i], if (GetModuleFileNameEx (handle, hmodules[i],
dll_name, sizeof (dll_name)) == 0) dll_name, sizeof (dll_name)) == 0)
continue; continue;
#ifdef __USEWIDE #ifdef __USEWIDE
@ -466,7 +447,7 @@ windows_add_dll (LPVOID load_addr)
/* See nat/windows-nat.h. */ /* See nat/windows-nat.h. */
void void
dll_loaded_event () windows_process_info::dll_loaded_event ()
{ {
gdb_assert (current_event.dwDebugEventCode == LOAD_DLL_DEBUG_EVENT); gdb_assert (current_event.dwDebugEventCode == LOAD_DLL_DEBUG_EVENT);
@ -478,29 +459,28 @@ dll_loaded_event ()
in the sense that it might be NULL. And the first DLL event in in the sense that it might be NULL. And the first DLL event in
particular is explicitly documented as "likely not pass[ed]" particular is explicitly documented as "likely not pass[ed]"
(source: MSDN LOAD_DLL_DEBUG_INFO structure). */ (source: MSDN LOAD_DLL_DEBUG_INFO structure). */
dll_name = get_image_name (current_process_handle, dll_name = get_image_name (handle, event->lpImageName, event->fUnicode);
event->lpImageName, event->fUnicode);
/* If the DLL name could not be gleaned via lpImageName, try harder /* If the DLL name could not be gleaned via lpImageName, try harder
by enumerating all the DLLs loaded into the inferior, looking for by enumerating all the DLLs loaded into the inferior, looking for
one that is loaded at base address = lpBaseOfDll. */ one that is loaded at base address = lpBaseOfDll. */
if (dll_name != nullptr) if (dll_name != nullptr)
handle_load_dll (dll_name, event->lpBaseOfDll); handle_load_dll (dll_name, event->lpBaseOfDll);
else if (event->lpBaseOfDll != nullptr) else if (event->lpBaseOfDll != nullptr)
windows_add_dll (event->lpBaseOfDll); add_dll (event->lpBaseOfDll);
} }
/* See nat/windows-nat.h. */ /* See nat/windows-nat.h. */
void void
windows_add_all_dlls () windows_process_info::add_all_dlls ()
{ {
windows_add_dll (nullptr); add_dll (nullptr);
} }
/* See nat/windows-nat.h. */ /* See nat/windows-nat.h. */
bool bool
matching_pending_stop (bool debug_events) windows_process_info::matching_pending_stop (bool debug_events)
{ {
/* If there are pending stops, and we might plausibly hit one of /* If there are pending stops, and we might plausibly hit one of
them, we don't want to actually continue the inferior -- we just them, we don't want to actually continue the inferior -- we just
@ -524,7 +504,7 @@ matching_pending_stop (bool debug_events)
/* See nat/windows-nat.h. */ /* See nat/windows-nat.h. */
gdb::optional<pending_stop> gdb::optional<pending_stop>
fetch_pending_stop (bool debug_events) windows_process_info::fetch_pending_stop (bool debug_events)
{ {
gdb::optional<pending_stop> result; gdb::optional<pending_stop> result;
for (auto iter = pending_stops.begin (); for (auto iter = pending_stops.begin ();

View file

@ -109,79 +109,6 @@ enum thread_disposition_type
INVALIDATE_CONTEXT INVALIDATE_CONTEXT
}; };
/* Find a thread record given a thread id. THREAD_DISPOSITION
controls whether the thread is suspended, and whether the context
is invalidated.
This function must be supplied by the embedding application. */
extern windows_thread_info *thread_rec (ptid_t ptid,
thread_disposition_type disposition);
/* Handle OUTPUT_DEBUG_STRING_EVENT from child process. Updates
OURSTATUS and returns the thread id if this represents a thread
change (this is specific to Cygwin), otherwise 0.
Cygwin prepends its messages with a "cygwin:". Interpret this as
a Cygwin signal. Otherwise just print the string as a warning.
This function must be supplied by the embedding application. */
extern int handle_output_debug_string (struct target_waitstatus *ourstatus);
/* Handle a DLL load event.
This function assumes that the current event did not occur during
inferior initialization.
DLL_NAME is the name of the library. BASE is the base load
address.
This function must be supplied by the embedding application. */
extern void handle_load_dll (const char *dll_name, LPVOID base);
/* Handle a DLL unload event.
This function assumes that this event did not occur during inferior
initialization.
This function must be supplied by the embedding application. */
extern void handle_unload_dll ();
/* Handle MS_VC_EXCEPTION when processing a stop. MS_VC_EXCEPTION is
somewhat undocumented but is used to tell the debugger the name of
a thread.
Return true if the exception was handled; return false otherwise.
This function must be supplied by the embedding application. */
extern bool handle_ms_vc_exception (const EXCEPTION_RECORD *rec);
/* When EXCEPTION_ACCESS_VIOLATION is processed, we give the embedding
application a chance to change it to be considered "unhandled".
This function must be supplied by the embedding application. If it
returns true, then the exception is "unhandled". */
extern bool handle_access_violation (const EXCEPTION_RECORD *rec);
/* Currently executing process */
extern HANDLE current_process_handle;
extern DWORD current_process_id;
extern DWORD main_thread_id;
extern enum gdb_signal last_sig;
/* The current debug event from WaitForDebugEvent or from a pending
stop. */
extern DEBUG_EVENT current_event;
/* The ID of the thread for which we anticipate a stop event.
Normally this is -1, meaning we'll accept an event in any
thread. */
extern DWORD desired_stop_thread_id;
/* A single pending stop. See "pending_stops" for more /* A single pending stop. See "pending_stops" for more
information. */ information. */
struct pending_stop struct pending_stop
@ -197,27 +124,6 @@ struct pending_stop
DEBUG_EVENT event; DEBUG_EVENT event;
}; };
/* A vector of pending stops. Sometimes, Windows will report a stop
on a thread that has been ostensibly suspended. We believe what
happens here is that two threads hit a breakpoint simultaneously,
and the Windows kernel queues the stop events. However, this can
result in the strange effect of trying to single step thread A --
leaving all other threads suspended -- and then seeing a stop in
thread B. To handle this scenario, we queue all such "pending"
stops here, and then process them once the step has completed. See
PR gdb/22992. */
extern std::vector<pending_stop> pending_stops;
/* Contents of $_siginfo */
extern EXCEPTION_RECORD siginfo_er;
#ifdef __x86_64__
/* The target is a WOW64 process */
extern bool wow64_process;
/* Ignore first breakpoint exception of WOW64 process */
extern bool ignore_first_breakpoint;
#endif
typedef enum typedef enum
{ {
HANDLE_EXCEPTION_UNHANDLED = 0, HANDLE_EXCEPTION_UNHANDLED = 0,
@ -225,29 +131,140 @@ typedef enum
HANDLE_EXCEPTION_IGNORED HANDLE_EXCEPTION_IGNORED
} handle_exception_result; } handle_exception_result;
extern handle_exception_result handle_exception /* A single Windows process. An object of this type (or subclass) is
(struct target_waitstatus *ourstatus, bool debug_exceptions); created by the client. Some methods must be provided by the client
as well. */
/* Call to indicate that a DLL was loaded. */ struct windows_process_info
{
/* The process handle */
HANDLE handle = 0;
DWORD id = 0;
DWORD main_thread_id = 0;
enum gdb_signal last_sig = GDB_SIGNAL_0;
extern void dll_loaded_event (); /* The current debug event from WaitForDebugEvent or from a pending
stop. */
DEBUG_EVENT current_event {};
/* Iterate over all DLLs currently mapped by our inferior, and /* The ID of the thread for which we anticipate a stop event.
add them to our list of solibs. */ Normally this is -1, meaning we'll accept an event in any
thread. */
DWORD desired_stop_thread_id = -1;
extern void windows_add_all_dlls (); /* A vector of pending stops. Sometimes, Windows will report a stop
on a thread that has been ostensibly suspended. We believe what
happens here is that two threads hit a breakpoint simultaneously,
and the Windows kernel queues the stop events. However, this can
result in the strange effect of trying to single step thread A --
leaving all other threads suspended -- and then seeing a stop in
thread B. To handle this scenario, we queue all such "pending"
stops here, and then process them once the step has completed. See
PR gdb/22992. */
std::vector<pending_stop> pending_stops;
/* Return true if there is a pending stop matching /* Contents of $_siginfo */
desired_stop_thread_id. If DEBUG_EVENTS is true, logging will be EXCEPTION_RECORD siginfo_er {};
enabled. */
extern bool matching_pending_stop (bool debug_events); #ifdef __x86_64__
/* The target is a WOW64 process */
bool wow64_process = false;
/* Ignore first breakpoint exception of WOW64 process */
bool ignore_first_breakpoint = false;
#endif
/* See if a pending stop matches DESIRED_STOP_THREAD_ID. If so,
remove it from the list of pending stops, set 'current_event', and
return it. Otherwise, return an empty optional. */
extern gdb::optional<pending_stop> fetch_pending_stop (bool debug_events); /* Find a thread record given a thread id. THREAD_DISPOSITION
controls whether the thread is suspended, and whether the context
is invalidated.
This function must be supplied by the embedding application. */
windows_thread_info *thread_rec (ptid_t ptid,
thread_disposition_type disposition);
/* Handle OUTPUT_DEBUG_STRING_EVENT from child process. Updates
OURSTATUS and returns the thread id if this represents a thread
change (this is specific to Cygwin), otherwise 0.
Cygwin prepends its messages with a "cygwin:". Interpret this as
a Cygwin signal. Otherwise just print the string as a warning.
This function must be supplied by the embedding application. */
int handle_output_debug_string (struct target_waitstatus *ourstatus);
/* Handle a DLL load event.
This function assumes that the current event did not occur during
inferior initialization.
DLL_NAME is the name of the library. BASE is the base load
address.
This function must be supplied by the embedding application. */
void handle_load_dll (const char *dll_name, LPVOID base);
/* Handle a DLL unload event.
This function assumes that this event did not occur during inferior
initialization.
This function must be supplied by the embedding application. */
void handle_unload_dll ();
/* Handle MS_VC_EXCEPTION when processing a stop. MS_VC_EXCEPTION is
somewhat undocumented but is used to tell the debugger the name of
a thread.
Return true if the exception was handled; return false otherwise.
This function must be supplied by the embedding application. */
bool handle_ms_vc_exception (const EXCEPTION_RECORD *rec);
/* When EXCEPTION_ACCESS_VIOLATION is processed, we give the embedding
application a chance to change it to be considered "unhandled".
This function must be supplied by the embedding application. If it
returns true, then the exception is "unhandled". */
bool handle_access_violation (const EXCEPTION_RECORD *rec);
handle_exception_result handle_exception
(struct target_waitstatus *ourstatus, bool debug_exceptions);
/* Call to indicate that a DLL was loaded. */
void dll_loaded_event ();
/* Iterate over all DLLs currently mapped by our inferior, and
add them to our list of solibs. */
void add_all_dlls ();
/* Return true if there is a pending stop matching
desired_stop_thread_id. If DEBUG_EVENTS is true, logging will be
enabled. */
bool matching_pending_stop (bool debug_events);
/* See if a pending stop matches DESIRED_STOP_THREAD_ID. If so,
remove it from the list of pending stops, set 'current_event', and
return it. Otherwise, return an empty optional. */
gdb::optional<pending_stop> fetch_pending_stop (bool debug_events);
private:
/* Iterate over all DLLs currently mapped by our inferior, looking for
a DLL which is loaded at LOAD_ADDR. If found, add the DLL to our
list of solibs; otherwise do nothing. LOAD_ADDR NULL means add all
DLLs to the list of solibs; this is used when the inferior finishes
its initialization, and all the DLLs it statically depends on are
presumed loaded. */
void add_dll (LPVOID load_addr);
};
/* A simple wrapper for ContinueDebugEvent that continues the last /* A simple wrapper for ContinueDebugEvent that continues the last
waited-for event. If DEBUG_EVENTS is true, logging will be waited-for event. If DEBUG_EVENTS is true, logging will be

View file

@ -74,6 +74,9 @@
using namespace windows_nat; using namespace windows_nat;
/* The current process. */
static windows_process_info windows_process;
#undef STARTUPINFO #undef STARTUPINFO
#undef CreateProcess #undef CreateProcess
#undef GetModuleFileNameEx #undef GetModuleFileNameEx
@ -242,7 +245,7 @@ struct windows_nat_target final : public x86_nat_target<inf_child_target>
bool stopped_by_sw_breakpoint () override bool stopped_by_sw_breakpoint () override
{ {
windows_thread_info *th windows_thread_info *th
= thread_rec (inferior_ptid, DONT_INVALIDATE_CONTEXT); = windows_process.thread_rec (inferior_ptid, DONT_INVALIDATE_CONTEXT);
return th->stopped_at_software_breakpoint; return th->stopped_at_software_breakpoint;
} }
@ -317,7 +320,8 @@ check (BOOL ok, const char *file, int line)
/* See nat/windows-nat.h. */ /* See nat/windows-nat.h. */
windows_thread_info * windows_thread_info *
windows_nat::thread_rec (ptid_t ptid, thread_disposition_type disposition) windows_nat::windows_process_info::thread_rec
(ptid_t ptid, thread_disposition_type disposition)
{ {
for (auto &th : thread_list) for (auto &th : thread_list)
if (th->tid == ptid.lwp ()) if (th->tid == ptid.lwp ())
@ -361,14 +365,14 @@ windows_add_thread (ptid_t ptid, HANDLE h, void *tlb, bool main_thread_p)
gdb_assert (ptid.lwp () != 0); gdb_assert (ptid.lwp () != 0);
if ((th = thread_rec (ptid, DONT_INVALIDATE_CONTEXT))) if ((th = windows_process.thread_rec (ptid, DONT_INVALIDATE_CONTEXT)))
return th; return th;
CORE_ADDR base = (CORE_ADDR) (uintptr_t) tlb; CORE_ADDR base = (CORE_ADDR) (uintptr_t) tlb;
#ifdef __x86_64__ #ifdef __x86_64__
/* For WOW64 processes, this is actually the pointer to the 64bit TIB, /* For WOW64 processes, this is actually the pointer to the 64bit TIB,
and the 32bit TIB is exactly 2 pages after it. */ and the 32bit TIB is exactly 2 pages after it. */
if (wow64_process) if (windows_process.wow64_process)
base += 0x2000; base += 0x2000;
#endif #endif
th = new windows_thread_info (ptid.lwp (), h, base); th = new windows_thread_info (ptid.lwp (), h, base);
@ -462,7 +466,7 @@ windows_fetch_one_register (struct regcache *regcache,
char *context_ptr = (char *) &th->context; char *context_ptr = (char *) &th->context;
#ifdef __x86_64__ #ifdef __x86_64__
if (wow64_process) if (windows_process.wow64_process)
context_ptr = (char *) &th->wow64_context; context_ptr = (char *) &th->wow64_context;
#endif #endif
@ -524,7 +528,8 @@ windows_fetch_one_register (struct regcache *regcache,
void void
windows_nat_target::fetch_registers (struct regcache *regcache, int r) windows_nat_target::fetch_registers (struct regcache *regcache, int r)
{ {
windows_thread_info *th = thread_rec (regcache->ptid (), INVALIDATE_CONTEXT); windows_thread_info *th
= windows_process.thread_rec (regcache->ptid (), INVALIDATE_CONTEXT);
/* Check if TH exists. Windows sometimes uses a non-existent /* Check if TH exists. Windows sometimes uses a non-existent
thread id in its events. */ thread id in its events. */
@ -547,7 +552,7 @@ windows_nat_target::fetch_registers (struct regcache *regcache, int r)
else else
#endif #endif
#ifdef __x86_64__ #ifdef __x86_64__
if (wow64_process) if (windows_process.wow64_process)
{ {
th->wow64_context.ContextFlags = CONTEXT_DEBUGGER_DR; th->wow64_context.ContextFlags = CONTEXT_DEBUGGER_DR;
CHECK (Wow64GetThreadContext (th->h, &th->wow64_context)); CHECK (Wow64GetThreadContext (th->h, &th->wow64_context));
@ -606,7 +611,7 @@ windows_store_one_register (const struct regcache *regcache,
char *context_ptr = (char *) &th->context; char *context_ptr = (char *) &th->context;
#ifdef __x86_64__ #ifdef __x86_64__
if (wow64_process) if (windows_process.wow64_process)
context_ptr = (char *) &th->wow64_context; context_ptr = (char *) &th->wow64_context;
#endif #endif
@ -619,7 +624,8 @@ windows_store_one_register (const struct regcache *regcache,
void void
windows_nat_target::store_registers (struct regcache *regcache, int r) windows_nat_target::store_registers (struct regcache *regcache, int r)
{ {
windows_thread_info *th = thread_rec (regcache->ptid (), INVALIDATE_CONTEXT); windows_thread_info *th
= windows_process.thread_rec (regcache->ptid (), INVALIDATE_CONTEXT);
/* Check if TH exists. Windows sometimes uses a non-existent /* Check if TH exists. Windows sometimes uses a non-existent
thread id in its events. */ thread id in its events. */
@ -762,7 +768,8 @@ windows_make_so (const char *name, LPVOID load_addr)
/* See nat/windows-nat.h. */ /* See nat/windows-nat.h. */
void void
windows_nat::handle_load_dll (const char *dll_name, LPVOID base) windows_nat::windows_process_info::handle_load_dll (const char *dll_name,
LPVOID base)
{ {
windows_solib *solib = windows_make_so (dll_name, base); windows_solib *solib = windows_make_so (dll_name, base);
DEBUG_EVENTS ("Loading dll \"%s\" at %s.", solib->name.c_str (), DEBUG_EVENTS ("Loading dll \"%s\" at %s.", solib->name.c_str (),
@ -772,7 +779,7 @@ windows_nat::handle_load_dll (const char *dll_name, LPVOID base)
/* See nat/windows-nat.h. */ /* See nat/windows-nat.h. */
void void
windows_nat::handle_unload_dll () windows_nat::windows_process_info::handle_unload_dll ()
{ {
LPVOID lpBaseOfDll = current_event.u.UnloadDll.lpBaseOfDll; LPVOID lpBaseOfDll = current_event.u.UnloadDll.lpBaseOfDll;
@ -804,22 +811,6 @@ windows_nat::handle_unload_dll ()
host_address_to_string (lpBaseOfDll)); host_address_to_string (lpBaseOfDll));
} }
/* Call FUNC wrapped in a TRY/CATCH that swallows all GDB
exceptions. */
static void
catch_errors (void (*func) ())
{
try
{
func ();
}
catch (const gdb_exception &ex)
{
exception_print (gdb_stderr, ex);
}
}
/* Clear list of loaded DLLs. */ /* Clear list of loaded DLLs. */
static void static void
windows_clear_solib (void) windows_clear_solib (void)
@ -849,7 +840,8 @@ signal_event_command (const char *args, int from_tty)
/* See nat/windows-nat.h. */ /* See nat/windows-nat.h. */
int int
windows_nat::handle_output_debug_string (struct target_waitstatus *ourstatus) windows_nat::windows_process_info::handle_output_debug_string
(struct target_waitstatus *ourstatus)
{ {
int retval = 0; int retval = 0;
@ -914,7 +906,7 @@ display_selector (HANDLE thread, DWORD sel)
LDT_ENTRY info; LDT_ENTRY info;
BOOL ret; BOOL ret;
#ifdef __x86_64__ #ifdef __x86_64__
if (wow64_process) if (windows_process.wow64_process)
ret = Wow64GetThreadSelectorEntry (thread, sel, &info); ret = Wow64GetThreadSelectorEntry (thread, sel, &info);
else else
#endif #endif
@ -1003,12 +995,12 @@ display_selectors (const char * args, int from_tty)
} }
windows_thread_info *current_windows_thread windows_thread_info *current_windows_thread
= thread_rec (inferior_ptid, DONT_INVALIDATE_CONTEXT); = windows_process.thread_rec (inferior_ptid, DONT_INVALIDATE_CONTEXT);
if (!args) if (!args)
{ {
#ifdef __x86_64__ #ifdef __x86_64__
if (wow64_process) if (windows_process.wow64_process)
{ {
gdb_puts ("Selector $cs\n"); gdb_puts ("Selector $cs\n");
display_selector (current_windows_thread->h, display_selector (current_windows_thread->h,
@ -1064,7 +1056,8 @@ display_selectors (const char * args, int from_tty)
/* See nat/windows-nat.h. */ /* See nat/windows-nat.h. */
bool bool
windows_nat::handle_ms_vc_exception (const EXCEPTION_RECORD *rec) windows_nat::windows_process_info::handle_ms_vc_exception
(const EXCEPTION_RECORD *rec)
{ {
if (rec->NumberParameters >= 3 if (rec->NumberParameters >= 3
&& (rec->ExceptionInformation[0] & 0xffffffff) == 0x1000) && (rec->ExceptionInformation[0] & 0xffffffff) == 0x1000)
@ -1103,7 +1096,8 @@ windows_nat::handle_ms_vc_exception (const EXCEPTION_RECORD *rec)
/* See nat/windows-nat.h. */ /* See nat/windows-nat.h. */
bool bool
windows_nat::handle_access_violation (const EXCEPTION_RECORD *rec) windows_nat::windows_process_info::handle_access_violation
(const EXCEPTION_RECORD *rec)
{ {
#ifdef __CYGWIN__ #ifdef __CYGWIN__
/* See if the access violation happened within the cygwin DLL /* See if the access violation happened within the cygwin DLL
@ -1134,16 +1128,16 @@ windows_continue (DWORD continue_status, int id, int killed)
{ {
BOOL res; BOOL res;
desired_stop_thread_id = id; windows_process.desired_stop_thread_id = id;
if (matching_pending_stop (debug_events)) if (windows_process.matching_pending_stop (debug_events))
return TRUE; return TRUE;
for (auto &th : thread_list) for (auto &th : thread_list)
if (id == -1 || id == (int) th->tid) if (id == -1 || id == (int) th->tid)
{ {
#ifdef __x86_64__ #ifdef __x86_64__
if (wow64_process) if (windows_process.wow64_process)
{ {
if (th->debug_registers_changed) if (th->debug_registers_changed)
{ {
@ -1225,9 +1219,10 @@ windows_continue (DWORD continue_status, int id, int killed)
static DWORD static DWORD
fake_create_process (void) fake_create_process (void)
{ {
current_process_handle = OpenProcess (PROCESS_ALL_ACCESS, FALSE, windows_process.handle
current_event.dwProcessId); = OpenProcess (PROCESS_ALL_ACCESS, FALSE,
if (current_process_handle != NULL) windows_process.current_event.dwProcessId);
if (windows_process.handle != NULL)
open_process_used = 1; open_process_used = 1;
else else
{ {
@ -1235,12 +1230,12 @@ fake_create_process (void)
(unsigned) GetLastError ()); (unsigned) GetLastError ());
/* We can not debug anything in that case. */ /* We can not debug anything in that case. */
} }
windows_add_thread (ptid_t (current_event.dwProcessId, 0, windows_add_thread (ptid_t (windows_process.current_event.dwProcessId, 0,
current_event.dwThreadId), windows_process.current_event.dwThreadId),
current_event.u.CreateThread.hThread, windows_process.current_event.u.CreateThread.hThread,
current_event.u.CreateThread.lpThreadLocalBase, windows_process.current_event.u.CreateThread.lpThreadLocalBase,
true /* main_thread_p */); true /* main_thread_p */);
return current_event.dwThreadId; return windows_process.current_event.dwThreadId;
} }
void void
@ -1259,11 +1254,12 @@ windows_nat_target::resume (ptid_t ptid, int step, enum gdb_signal sig)
if (sig != GDB_SIGNAL_0) if (sig != GDB_SIGNAL_0)
{ {
if (current_event.dwDebugEventCode != EXCEPTION_DEBUG_EVENT) if (windows_process.current_event.dwDebugEventCode
!= EXCEPTION_DEBUG_EVENT)
{ {
DEBUG_EXCEPT ("Cannot continue with signal %d here.", sig); DEBUG_EXCEPT ("Cannot continue with signal %d here.", sig);
} }
else if (sig == last_sig) else if (sig == windows_process.last_sig)
continue_status = DBG_EXCEPTION_NOT_HANDLED; continue_status = DBG_EXCEPTION_NOT_HANDLED;
else else
#if 0 #if 0
@ -1287,20 +1283,20 @@ windows_nat_target::resume (ptid_t ptid, int step, enum gdb_signal sig)
} }
#endif #endif
DEBUG_EXCEPT ("Can only continue with received signal %d.", DEBUG_EXCEPT ("Can only continue with received signal %d.",
last_sig); windows_process.last_sig);
} }
last_sig = GDB_SIGNAL_0; windows_process.last_sig = GDB_SIGNAL_0;
DEBUG_EXEC ("pid=%d, tid=0x%x, step=%d, sig=%d", DEBUG_EXEC ("pid=%d, tid=0x%x, step=%d, sig=%d",
ptid.pid (), (unsigned) ptid.lwp (), step, sig); ptid.pid (), (unsigned) ptid.lwp (), step, sig);
/* Get context for currently selected thread. */ /* Get context for currently selected thread. */
th = thread_rec (inferior_ptid, DONT_INVALIDATE_CONTEXT); th = windows_process.thread_rec (inferior_ptid, DONT_INVALIDATE_CONTEXT);
if (th) if (th)
{ {
#ifdef __x86_64__ #ifdef __x86_64__
if (wow64_process) if (windows_process.wow64_process)
{ {
if (step) if (step)
{ {
@ -1385,7 +1381,7 @@ ctrl_c_handler (DWORD event_type)
return TRUE; return TRUE;
#ifdef __x86_64__ #ifdef __x86_64__
if (wow64_process) if (windows_process.wow64_process)
{ {
/* Call DbgUiRemoteBreakin of the 32bit ntdll.dll in the target process. /* Call DbgUiRemoteBreakin of the 32bit ntdll.dll in the target process.
DebugBreakProcess would call the one of the 64bit ntdll.dll, which DebugBreakProcess would call the one of the 64bit ntdll.dll, which
@ -1400,7 +1396,7 @@ ctrl_c_handler (DWORD event_type)
if (wow64_dbgbreak != nullptr) if (wow64_dbgbreak != nullptr)
{ {
HANDLE thread = CreateRemoteThread (current_process_handle, NULL, HANDLE thread = CreateRemoteThread (windows_process.handle, NULL,
0, (LPTHREAD_START_ROUTINE) 0, (LPTHREAD_START_ROUTINE)
wow64_dbgbreak, NULL, 0, NULL); wow64_dbgbreak, NULL, 0, NULL);
if (thread) if (thread)
@ -1410,7 +1406,7 @@ ctrl_c_handler (DWORD event_type)
else else
#endif #endif
{ {
if (!DebugBreakProcess (current_process_handle)) if (!DebugBreakProcess (windows_process.handle))
warning (_("Could not interrupt program. " warning (_("Could not interrupt program. "
"Press Ctrl-c in the program console.")); "Press Ctrl-c in the program console."));
} }
@ -1433,27 +1429,31 @@ windows_nat_target::get_windows_debug_event (int pid,
/* If there is a relevant pending stop, report it now. See the /* If there is a relevant pending stop, report it now. See the
comment by the definition of "pending_stops" for details on why comment by the definition of "pending_stops" for details on why
this is needed. */ this is needed. */
gdb::optional<pending_stop> stop = fetch_pending_stop (debug_events); gdb::optional<pending_stop> stop
= windows_process.fetch_pending_stop (debug_events);
if (stop.has_value ()) if (stop.has_value ())
{ {
thread_id = stop->thread_id; thread_id = stop->thread_id;
*ourstatus = stop->status; *ourstatus = stop->status;
ptid_t ptid (current_event.dwProcessId, thread_id); ptid_t ptid (windows_process.current_event.dwProcessId, thread_id);
windows_thread_info *th = thread_rec (ptid, INVALIDATE_CONTEXT); windows_thread_info *th
= windows_process.thread_rec (ptid, INVALIDATE_CONTEXT);
th->reload_context = true; th->reload_context = true;
return thread_id; return thread_id;
} }
last_sig = GDB_SIGNAL_0; windows_process.last_sig = GDB_SIGNAL_0;
DEBUG_EVENT *current_event = &windows_process.current_event;
if (!(debug_event = wait_for_debug_event (&current_event, 1000))) if (!(debug_event = wait_for_debug_event (&windows_process.current_event,
1000)))
goto out; goto out;
continue_status = DBG_CONTINUE; continue_status = DBG_CONTINUE;
event_code = current_event.dwDebugEventCode; event_code = windows_process.current_event.dwDebugEventCode;
ourstatus->set_spurious (); ourstatus->set_spurious ();
have_saved_context = 0; have_saved_context = 0;
@ -1461,12 +1461,12 @@ windows_nat_target::get_windows_debug_event (int pid,
{ {
case CREATE_THREAD_DEBUG_EVENT: case CREATE_THREAD_DEBUG_EVENT:
DEBUG_EVENTS ("kernel event for pid=%u tid=0x%x code=%s", DEBUG_EVENTS ("kernel event for pid=%u tid=0x%x code=%s",
(unsigned) current_event.dwProcessId, (unsigned) current_event->dwProcessId,
(unsigned) current_event.dwThreadId, (unsigned) current_event->dwThreadId,
"CREATE_THREAD_DEBUG_EVENT"); "CREATE_THREAD_DEBUG_EVENT");
if (saw_create != 1) if (saw_create != 1)
{ {
inferior *inf = find_inferior_pid (this, current_event.dwProcessId); inferior *inf = find_inferior_pid (this, current_event->dwProcessId);
if (!saw_create && inf->attach_flag) if (!saw_create && inf->attach_flag)
{ {
/* Kludge around a Windows bug where first event is a create /* Kludge around a Windows bug where first event is a create
@ -1479,64 +1479,64 @@ windows_nat_target::get_windows_debug_event (int pid,
break; break;
} }
/* Record the existence of this thread. */ /* Record the existence of this thread. */
thread_id = current_event.dwThreadId; thread_id = current_event->dwThreadId;
windows_add_thread windows_add_thread
(ptid_t (current_event.dwProcessId, current_event.dwThreadId, 0), (ptid_t (current_event->dwProcessId, current_event->dwThreadId, 0),
current_event.u.CreateThread.hThread, current_event->u.CreateThread.hThread,
current_event.u.CreateThread.lpThreadLocalBase, current_event->u.CreateThread.lpThreadLocalBase,
false /* main_thread_p */); false /* main_thread_p */);
break; break;
case EXIT_THREAD_DEBUG_EVENT: case EXIT_THREAD_DEBUG_EVENT:
DEBUG_EVENTS ("kernel event for pid=%u tid=0x%x code=%s", DEBUG_EVENTS ("kernel event for pid=%u tid=0x%x code=%s",
(unsigned) current_event.dwProcessId, (unsigned) current_event->dwProcessId,
(unsigned) current_event.dwThreadId, (unsigned) current_event->dwThreadId,
"EXIT_THREAD_DEBUG_EVENT"); "EXIT_THREAD_DEBUG_EVENT");
windows_delete_thread (ptid_t (current_event.dwProcessId, windows_delete_thread (ptid_t (current_event->dwProcessId,
current_event.dwThreadId, 0), current_event->dwThreadId, 0),
current_event.u.ExitThread.dwExitCode, current_event->u.ExitThread.dwExitCode,
false /* main_thread_p */); false /* main_thread_p */);
break; break;
case CREATE_PROCESS_DEBUG_EVENT: case CREATE_PROCESS_DEBUG_EVENT:
DEBUG_EVENTS ("kernel event for pid=%u tid=0x%x code=%s", DEBUG_EVENTS ("kernel event for pid=%u tid=0x%x code=%s",
(unsigned) current_event.dwProcessId, (unsigned) current_event->dwProcessId,
(unsigned) current_event.dwThreadId, (unsigned) current_event->dwThreadId,
"CREATE_PROCESS_DEBUG_EVENT"); "CREATE_PROCESS_DEBUG_EVENT");
CloseHandle (current_event.u.CreateProcessInfo.hFile); CloseHandle (current_event->u.CreateProcessInfo.hFile);
if (++saw_create != 1) if (++saw_create != 1)
break; break;
current_process_handle = current_event.u.CreateProcessInfo.hProcess; windows_process.handle = current_event->u.CreateProcessInfo.hProcess;
/* Add the main thread. */ /* Add the main thread. */
windows_add_thread windows_add_thread
(ptid_t (current_event.dwProcessId, (ptid_t (current_event->dwProcessId,
current_event.dwThreadId, 0), current_event->dwThreadId, 0),
current_event.u.CreateProcessInfo.hThread, current_event->u.CreateProcessInfo.hThread,
current_event.u.CreateProcessInfo.lpThreadLocalBase, current_event->u.CreateProcessInfo.lpThreadLocalBase,
true /* main_thread_p */); true /* main_thread_p */);
thread_id = current_event.dwThreadId; thread_id = current_event->dwThreadId;
break; break;
case EXIT_PROCESS_DEBUG_EVENT: case EXIT_PROCESS_DEBUG_EVENT:
DEBUG_EVENTS ("kernel event for pid=%u tid=0x%x code=%s", DEBUG_EVENTS ("kernel event for pid=%u tid=0x%x code=%s",
(unsigned) current_event.dwProcessId, (unsigned) current_event->dwProcessId,
(unsigned) current_event.dwThreadId, (unsigned) current_event->dwThreadId,
"EXIT_PROCESS_DEBUG_EVENT"); "EXIT_PROCESS_DEBUG_EVENT");
if (!windows_initialization_done) if (!windows_initialization_done)
{ {
target_terminal::ours (); target_terminal::ours ();
target_mourn_inferior (inferior_ptid); target_mourn_inferior (inferior_ptid);
error (_("During startup program exited with code 0x%x."), error (_("During startup program exited with code 0x%x."),
(unsigned int) current_event.u.ExitProcess.dwExitCode); (unsigned int) current_event->u.ExitProcess.dwExitCode);
} }
else if (saw_create == 1) else if (saw_create == 1)
{ {
windows_delete_thread (ptid_t (current_event.dwProcessId, windows_delete_thread (ptid_t (current_event->dwProcessId,
current_event.dwThreadId, 0), current_event->dwThreadId, 0),
0, true /* main_thread_p */); 0, true /* main_thread_p */);
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 /* If the exit status looks like a fatal exception, but we
don't recognize the exception's code, make the original don't recognize the exception's code, make the original
exit status value available, to avoid losing exit status value available, to avoid losing
@ -1548,50 +1548,64 @@ windows_nat_target::get_windows_debug_event (int pid,
else else
ourstatus->set_signalled (gdb_signal_from_host (exit_signal)); ourstatus->set_signalled (gdb_signal_from_host (exit_signal));
thread_id = current_event.dwThreadId; thread_id = current_event->dwThreadId;
} }
break; break;
case LOAD_DLL_DEBUG_EVENT: case LOAD_DLL_DEBUG_EVENT:
DEBUG_EVENTS ("kernel event for pid=%u tid=0x%x code=%s", DEBUG_EVENTS ("kernel event for pid=%u tid=0x%x code=%s",
(unsigned) current_event.dwProcessId, (unsigned) current_event->dwProcessId,
(unsigned) current_event.dwThreadId, (unsigned) current_event->dwThreadId,
"LOAD_DLL_DEBUG_EVENT"); "LOAD_DLL_DEBUG_EVENT");
CloseHandle (current_event.u.LoadDll.hFile); CloseHandle (current_event->u.LoadDll.hFile);
if (saw_create != 1 || ! windows_initialization_done) if (saw_create != 1 || ! windows_initialization_done)
break; break;
catch_errors (dll_loaded_event); try
{
windows_process.dll_loaded_event ();
}
catch (const gdb_exception &ex)
{
exception_print (gdb_stderr, ex);
}
ourstatus->set_loaded (); ourstatus->set_loaded ();
thread_id = current_event.dwThreadId; thread_id = current_event->dwThreadId;
break; break;
case UNLOAD_DLL_DEBUG_EVENT: case UNLOAD_DLL_DEBUG_EVENT:
DEBUG_EVENTS ("kernel event for pid=%u tid=0x%x code=%s", DEBUG_EVENTS ("kernel event for pid=%u tid=0x%x code=%s",
(unsigned) current_event.dwProcessId, (unsigned) current_event->dwProcessId,
(unsigned) current_event.dwThreadId, (unsigned) current_event->dwThreadId,
"UNLOAD_DLL_DEBUG_EVENT"); "UNLOAD_DLL_DEBUG_EVENT");
if (saw_create != 1 || ! windows_initialization_done) if (saw_create != 1 || ! windows_initialization_done)
break; break;
catch_errors (handle_unload_dll); try
{
windows_process.handle_unload_dll ();
}
catch (const gdb_exception &ex)
{
exception_print (gdb_stderr, ex);
}
ourstatus->set_loaded (); ourstatus->set_loaded ();
thread_id = current_event.dwThreadId; thread_id = current_event->dwThreadId;
break; break;
case EXCEPTION_DEBUG_EVENT: case EXCEPTION_DEBUG_EVENT:
DEBUG_EVENTS ("kernel event for pid=%u tid=0x%x code=%s", DEBUG_EVENTS ("kernel event for pid=%u tid=0x%x code=%s",
(unsigned) current_event.dwProcessId, (unsigned) current_event->dwProcessId,
(unsigned) current_event.dwThreadId, (unsigned) current_event->dwThreadId,
"EXCEPTION_DEBUG_EVENT"); "EXCEPTION_DEBUG_EVENT");
if (saw_create != 1) if (saw_create != 1)
break; break;
switch (handle_exception (ourstatus, debug_exceptions)) switch (windows_process.handle_exception (ourstatus, debug_exceptions))
{ {
case HANDLE_EXCEPTION_UNHANDLED: case HANDLE_EXCEPTION_UNHANDLED:
default: default:
continue_status = DBG_EXCEPTION_NOT_HANDLED; continue_status = DBG_EXCEPTION_NOT_HANDLED;
break; break;
case HANDLE_EXCEPTION_HANDLED: case HANDLE_EXCEPTION_HANDLED:
thread_id = current_event.dwThreadId; thread_id = current_event->dwThreadId;
break; break;
case HANDLE_EXCEPTION_IGNORED: case HANDLE_EXCEPTION_IGNORED:
continue_status = DBG_CONTINUE; continue_status = DBG_CONTINUE;
@ -1601,52 +1615,57 @@ windows_nat_target::get_windows_debug_event (int pid,
case OUTPUT_DEBUG_STRING_EVENT: /* Message from the kernel. */ case OUTPUT_DEBUG_STRING_EVENT: /* Message from the kernel. */
DEBUG_EVENTS ("kernel event for pid=%u tid=0x%x code=%s", DEBUG_EVENTS ("kernel event for pid=%u tid=0x%x code=%s",
(unsigned) current_event.dwProcessId, (unsigned) current_event->dwProcessId,
(unsigned) current_event.dwThreadId, (unsigned) current_event->dwThreadId,
"OUTPUT_DEBUG_STRING_EVENT"); "OUTPUT_DEBUG_STRING_EVENT");
if (saw_create != 1) if (saw_create != 1)
break; break;
thread_id = handle_output_debug_string (ourstatus); thread_id = windows_process.handle_output_debug_string (ourstatus);
break; break;
default: default:
if (saw_create != 1) if (saw_create != 1)
break; break;
gdb_printf ("gdb: kernel event for pid=%u tid=0x%x\n", gdb_printf ("gdb: kernel event for pid=%u tid=0x%x\n",
(unsigned) current_event.dwProcessId, (unsigned) current_event->dwProcessId,
(unsigned) current_event.dwThreadId); (unsigned) current_event->dwThreadId);
gdb_printf (" unknown event code %u\n", gdb_printf (" unknown event code %u\n",
(unsigned) current_event.dwDebugEventCode); (unsigned) current_event->dwDebugEventCode);
break; break;
} }
if (!thread_id || saw_create != 1) if (!thread_id || saw_create != 1)
{ {
CHECK (windows_continue (continue_status, desired_stop_thread_id, 0)); CHECK (windows_continue (continue_status,
windows_process.desired_stop_thread_id, 0));
} }
else if (desired_stop_thread_id != -1 && desired_stop_thread_id != thread_id) else if (windows_process.desired_stop_thread_id != -1
&& windows_process.desired_stop_thread_id != thread_id)
{ {
/* Pending stop. See the comment by the definition of /* Pending stop. See the comment by the definition of
"pending_stops" for details on why this is needed. */ "pending_stops" for details on why this is needed. */
DEBUG_EVENTS ("get_windows_debug_event - " DEBUG_EVENTS ("get_windows_debug_event - "
"unexpected stop in 0x%x (expecting 0x%x)", "unexpected stop in 0x%x (expecting 0x%x)",
thread_id, desired_stop_thread_id); thread_id, windows_process.desired_stop_thread_id);
if (current_event.dwDebugEventCode == EXCEPTION_DEBUG_EVENT if (current_event->dwDebugEventCode == EXCEPTION_DEBUG_EVENT
&& ((current_event.u.Exception.ExceptionRecord.ExceptionCode && ((current_event->u.Exception.ExceptionRecord.ExceptionCode
== EXCEPTION_BREAKPOINT) == EXCEPTION_BREAKPOINT)
|| (current_event.u.Exception.ExceptionRecord.ExceptionCode || (current_event->u.Exception.ExceptionRecord.ExceptionCode
== STATUS_WX86_BREAKPOINT)) == STATUS_WX86_BREAKPOINT))
&& windows_initialization_done) && windows_initialization_done)
{ {
ptid_t ptid = ptid_t (current_event.dwProcessId, thread_id, 0); ptid_t ptid = ptid_t (current_event->dwProcessId, thread_id, 0);
windows_thread_info *th = thread_rec (ptid, INVALIDATE_CONTEXT); windows_thread_info *th
= windows_process.thread_rec (ptid, INVALIDATE_CONTEXT);
th->stopped_at_software_breakpoint = true; th->stopped_at_software_breakpoint = true;
th->pc_adjusted = false; th->pc_adjusted = false;
} }
pending_stops.push_back ({thread_id, *ourstatus, current_event}); windows_process.pending_stops.push_back
({thread_id, *ourstatus, windows_process.current_event});
thread_id = 0; thread_id = 0;
CHECK (windows_continue (continue_status, desired_stop_thread_id, 0)); CHECK (windows_continue (continue_status,
windows_process.desired_stop_thread_id, 0));
} }
out: out:
@ -1702,20 +1721,23 @@ windows_nat_target::wait (ptid_t ptid, struct target_waitstatus *ourstatus,
if (retval) if (retval)
{ {
ptid_t result = ptid_t (current_event.dwProcessId, retval, 0); ptid_t result = ptid_t (windows_process.current_event.dwProcessId,
retval, 0);
if (ourstatus->kind () != TARGET_WAITKIND_EXITED if (ourstatus->kind () != TARGET_WAITKIND_EXITED
&& ourstatus->kind () != TARGET_WAITKIND_SIGNALLED) && ourstatus->kind () != TARGET_WAITKIND_SIGNALLED)
{ {
windows_thread_info *th = thread_rec (result, INVALIDATE_CONTEXT); windows_thread_info *th
= windows_process.thread_rec (result, INVALIDATE_CONTEXT);
if (th != nullptr) if (th != nullptr)
{ {
th->stopped_at_software_breakpoint = false; th->stopped_at_software_breakpoint = false;
if (current_event.dwDebugEventCode == EXCEPTION_DEBUG_EVENT if (windows_process.current_event.dwDebugEventCode
&& ((current_event.u.Exception.ExceptionRecord.ExceptionCode == EXCEPTION_DEBUG_EVENT
&& ((windows_process.current_event.u.Exception.ExceptionRecord.ExceptionCode
== EXCEPTION_BREAKPOINT) == EXCEPTION_BREAKPOINT)
|| (current_event.u.Exception.ExceptionRecord.ExceptionCode || (windows_process.current_event.u.Exception.ExceptionRecord.ExceptionCode
== STATUS_WX86_BREAKPOINT)) == STATUS_WX86_BREAKPOINT))
&& windows_initialization_done) && windows_initialization_done)
{ {
@ -1746,15 +1768,16 @@ windows_nat_target::do_initial_windows_stuff (DWORD pid, bool attaching)
int i; int i;
struct inferior *inf; struct inferior *inf;
last_sig = GDB_SIGNAL_0; windows_process.last_sig = GDB_SIGNAL_0;
open_process_used = 0; open_process_used = 0;
for (i = 0; i < sizeof (dr) / sizeof (dr[0]); i++) for (i = 0; i < sizeof (dr) / sizeof (dr[0]); i++)
dr[i] = 0; dr[i] = 0;
#ifdef __CYGWIN__ #ifdef __CYGWIN__
cygwin_load_start = cygwin_load_end = 0; cygwin_load_start = cygwin_load_end = 0;
#endif #endif
current_event.dwProcessId = pid; windows_process.current_event.dwProcessId = pid;
memset (&current_event, 0, sizeof (current_event)); memset (&windows_process.current_event, 0,
sizeof (windows_process.current_event));
inf = current_inferior (); inf = current_inferior ();
if (!inf->target_is_pushed (this)) if (!inf->target_is_pushed (this))
inf->push_target (this); inf->push_target (this);
@ -1764,9 +1787,10 @@ windows_nat_target::do_initial_windows_stuff (DWORD pid, bool attaching)
init_wait_for_inferior (); init_wait_for_inferior ();
#ifdef __x86_64__ #ifdef __x86_64__
ignore_first_breakpoint = !attaching && wow64_process; windows_process.ignore_first_breakpoint
= !attaching && windows_process.wow64_process;
if (!wow64_process) if (!windows_process.wow64_process)
{ {
windows_set_context_register_offsets (amd64_mappings); windows_set_context_register_offsets (amd64_mappings);
windows_set_segment_register_p (amd64_windows_segment_register_p); windows_set_segment_register_p (amd64_windows_segment_register_p);
@ -1820,7 +1844,7 @@ windows_nat_target::do_initial_windows_stuff (DWORD pid, bool attaching)
Rather than try to work around this sort of issue, it is much Rather than try to work around this sort of issue, it is much
simpler to just ignore DLL load/unload events during the startup simpler to just ignore DLL load/unload events during the startup
phase, and then process them all in one batch now. */ phase, and then process them all in one batch now. */
windows_add_all_dlls (); windows_process.add_all_dlls ();
windows_initialization_done = 1; windows_initialization_done = 1;
return; return;
@ -1918,7 +1942,7 @@ windows_nat_target::attach (const char *args, int from_tty)
{ {
BOOL wow64; BOOL wow64;
if (IsWow64Process (h, &wow64)) if (IsWow64Process (h, &wow64))
wow64_process = wow64; windows_process.wow64_process = wow64;
CloseHandle (h); CloseHandle (h);
} }
#endif #endif
@ -1935,10 +1959,11 @@ windows_nat_target::detach (inferior *inf, int from_tty)
ptid_t ptid = minus_one_ptid; ptid_t ptid = minus_one_ptid;
resume (ptid, 0, GDB_SIGNAL_0); resume (ptid, 0, GDB_SIGNAL_0);
if (!DebugActiveProcessStop (current_event.dwProcessId)) if (!DebugActiveProcessStop (windows_process.current_event.dwProcessId))
{ {
error (_("Can't detach process %u (error %u)"), error (_("Can't detach process %u (error %u)"),
(unsigned) current_event.dwProcessId, (unsigned) GetLastError ()); (unsigned) windows_process.current_event.dwProcessId,
(unsigned) GetLastError ());
detached = 0; detached = 0;
} }
DebugSetProcessKillOnExit (FALSE); DebugSetProcessKillOnExit (FALSE);
@ -1972,18 +1997,20 @@ windows_get_exec_module_filename (char *exe_name_ret, size_t exe_name_max_len)
cbNeeded = 0; cbNeeded = 0;
#ifdef __x86_64__ #ifdef __x86_64__
if (wow64_process) if (windows_process.wow64_process)
{ {
if (!EnumProcessModulesEx (current_process_handle, &dh_buf, if (!EnumProcessModulesEx (windows_process.handle,
sizeof (HMODULE), &cbNeeded, &dh_buf, sizeof (HMODULE), &cbNeeded,
LIST_MODULES_32BIT) || !cbNeeded) LIST_MODULES_32BIT)
|| !cbNeeded)
return 0; return 0;
} }
else else
#endif #endif
{ {
if (!EnumProcessModules (current_process_handle, &dh_buf, if (!EnumProcessModules (windows_process.handle,
sizeof (HMODULE), &cbNeeded) || !cbNeeded) &dh_buf, sizeof (HMODULE), &cbNeeded)
|| !cbNeeded)
return 0; return 0;
} }
@ -2007,7 +2034,7 @@ windows_get_exec_module_filename (char *exe_name_ret, size_t exe_name_max_len)
error (_("Error converting executable filename to POSIX: %d."), errno); error (_("Error converting executable filename to POSIX: %d."), errno);
} }
#else #else
len = GetModuleFileNameEx (current_process_handle, len = GetModuleFileNameEx (windows_process.handle,
dh_buf, exe_name_ret, exe_name_max_len); dh_buf, exe_name_ret, exe_name_max_len);
if (len == 0) if (len == 0)
error (_("Error getting executable filename: %u."), error (_("Error getting executable filename: %u."),
@ -2748,7 +2775,7 @@ windows_nat_target::create_inferior (const char *exec_file,
#ifdef __x86_64__ #ifdef __x86_64__
BOOL wow64; BOOL wow64;
if (IsWow64Process (pi.hProcess, &wow64)) if (IsWow64Process (pi.hProcess, &wow64))
wow64_process = wow64; windows_process.wow64_process = wow64;
#endif #endif
CloseHandle (pi.hThread); CloseHandle (pi.hThread);
@ -2771,10 +2798,10 @@ windows_nat_target::mourn_inferior ()
x86_cleanup_dregs(); x86_cleanup_dregs();
if (open_process_used) if (open_process_used)
{ {
CHECK (CloseHandle (current_process_handle)); CHECK (CloseHandle (windows_process.handle));
open_process_used = 0; open_process_used = 0;
} }
siginfo_er.ExceptionCode = 0; windows_process.siginfo_er.ExceptionCode = 0;
inf_child_target::mourn_inferior (); inf_child_target::mourn_inferior ();
} }
@ -2785,7 +2812,8 @@ void
windows_nat_target::interrupt () windows_nat_target::interrupt ()
{ {
DEBUG_EVENTS ("GenerateConsoleCtrlEvent (CTRLC_EVENT, 0)"); DEBUG_EVENTS ("GenerateConsoleCtrlEvent (CTRLC_EVENT, 0)");
CHECK (GenerateConsoleCtrlEvent (CTRL_C_EVENT, current_event.dwProcessId)); CHECK (GenerateConsoleCtrlEvent (CTRL_C_EVENT,
windows_process.current_event.dwProcessId));
registers_changed (); /* refresh register state */ registers_changed (); /* refresh register state */
} }
@ -2804,19 +2832,19 @@ windows_xfer_memory (gdb_byte *readbuf, const gdb_byte *writebuf,
{ {
DEBUG_MEM ("write target memory, %s bytes at %s", DEBUG_MEM ("write target memory, %s bytes at %s",
pulongest (len), core_addr_to_string (memaddr)); pulongest (len), core_addr_to_string (memaddr));
success = WriteProcessMemory (current_process_handle, success = WriteProcessMemory (windows_process.handle,
(LPVOID) (uintptr_t) memaddr, writebuf, (LPVOID) (uintptr_t) memaddr, writebuf,
len, &done); len, &done);
if (!success) if (!success)
lasterror = GetLastError (); lasterror = GetLastError ();
FlushInstructionCache (current_process_handle, FlushInstructionCache (windows_process.handle,
(LPCVOID) (uintptr_t) memaddr, len); (LPCVOID) (uintptr_t) memaddr, len);
} }
else else
{ {
DEBUG_MEM ("read target memory, %s bytes at %s", DEBUG_MEM ("read target memory, %s bytes at %s",
pulongest (len), core_addr_to_string (memaddr)); pulongest (len), core_addr_to_string (memaddr));
success = ReadProcessMemory (current_process_handle, success = ReadProcessMemory (windows_process.handle,
(LPCVOID) (uintptr_t) memaddr, readbuf, (LPCVOID) (uintptr_t) memaddr, readbuf,
len, &done); len, &done);
if (!success) if (!success)
@ -2832,15 +2860,16 @@ windows_xfer_memory (gdb_byte *readbuf, const gdb_byte *writebuf,
void void
windows_nat_target::kill () windows_nat_target::kill ()
{ {
CHECK (TerminateProcess (current_process_handle, 0)); CHECK (TerminateProcess (windows_process.handle, 0));
for (;;) for (;;)
{ {
if (!windows_continue (DBG_CONTINUE, -1, 1)) if (!windows_continue (DBG_CONTINUE, -1, 1))
break; break;
if (!wait_for_debug_event (&current_event, INFINITE)) if (!wait_for_debug_event (&windows_process.current_event, INFINITE))
break; break;
if (current_event.dwDebugEventCode == EXIT_PROCESS_DEBUG_EVENT) if (windows_process.current_event.dwDebugEventCode
== EXIT_PROCESS_DEBUG_EVENT)
break; break;
} }
@ -2906,28 +2935,31 @@ static enum target_xfer_status
windows_xfer_siginfo (gdb_byte *readbuf, ULONGEST offset, ULONGEST len, windows_xfer_siginfo (gdb_byte *readbuf, ULONGEST offset, ULONGEST len,
ULONGEST *xfered_len) ULONGEST *xfered_len)
{ {
char *buf = (char *) &siginfo_er; char *buf = (char *) &windows_process.siginfo_er;
size_t bufsize = sizeof (siginfo_er); size_t bufsize = sizeof (windows_process.siginfo_er);
#ifdef __x86_64__ #ifdef __x86_64__
EXCEPTION_RECORD32 er32; EXCEPTION_RECORD32 er32;
if (wow64_process) if (windows_process.wow64_process)
{ {
buf = (char *) &er32; buf = (char *) &er32;
bufsize = sizeof (er32); bufsize = sizeof (er32);
er32.ExceptionCode = siginfo_er.ExceptionCode; er32.ExceptionCode = windows_process.siginfo_er.ExceptionCode;
er32.ExceptionFlags = siginfo_er.ExceptionFlags; er32.ExceptionFlags = windows_process.siginfo_er.ExceptionFlags;
er32.ExceptionRecord = (uintptr_t) siginfo_er.ExceptionRecord; er32.ExceptionRecord
er32.ExceptionAddress = (uintptr_t) siginfo_er.ExceptionAddress; = (uintptr_t) windows_process.siginfo_er.ExceptionRecord;
er32.NumberParameters = siginfo_er.NumberParameters; er32.ExceptionAddress
= (uintptr_t) windows_process.siginfo_er.ExceptionAddress;
er32.NumberParameters = windows_process.siginfo_er.NumberParameters;
int i; int i;
for (i = 0; i < EXCEPTION_MAXIMUM_PARAMETERS; 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 #endif
if (siginfo_er.ExceptionCode == 0) if (windows_process.siginfo_er.ExceptionCode == 0)
return TARGET_XFER_E_IO; return TARGET_XFER_E_IO;
if (readbuf == nullptr) if (readbuf == nullptr)
@ -2985,7 +3017,7 @@ windows_nat_target::get_tib_address (ptid_t ptid, CORE_ADDR *addr)
{ {
windows_thread_info *th; windows_thread_info *th;
th = thread_rec (ptid, DONT_INVALIDATE_CONTEXT); th = windows_process.thread_rec (ptid, DONT_INVALIDATE_CONTEXT);
if (th == NULL) if (th == NULL)
return false; return false;
@ -3006,7 +3038,8 @@ windows_nat_target::get_ada_task_ptid (long lwp, ULONGEST thread)
const char * const char *
windows_nat_target::thread_name (struct thread_info *thr) windows_nat_target::thread_name (struct thread_info *thr)
{ {
return thread_rec (thr->ptid, DONT_INVALIDATE_CONTEXT)->name.get (); return windows_process.thread_rec (thr->ptid,
DONT_INVALIDATE_CONTEXT)->name.get ();
} }
@ -3178,8 +3211,9 @@ windows_nat_target::thread_alive (ptid_t ptid)
{ {
gdb_assert (ptid.lwp () != 0); gdb_assert (ptid.lwp () != 0);
return (WaitForSingleObject (thread_rec (ptid, DONT_INVALIDATE_CONTEXT)->h, 0) windows_thread_info *th
!= WAIT_OBJECT_0); = windows_process.thread_rec (ptid, DONT_INVALIDATE_CONTEXT);
return WaitForSingleObject (th->h, 0) != WAIT_OBJECT_0;
} }
void _initialize_check_for_gdb_ini (); void _initialize_check_for_gdb_ini ();

View file

@ -38,6 +38,8 @@
using namespace windows_nat; using namespace windows_nat;
static windows_process_info windows_process;
#ifndef USE_WIN32API #ifndef USE_WIN32API
#include <sys/cygwin.h> #include <sys/cygwin.h>
#endif #endif
@ -163,7 +165,8 @@ win32_require_context (windows_thread_info *th)
/* See nat/windows-nat.h. */ /* See nat/windows-nat.h. */
windows_thread_info * windows_thread_info *
windows_nat::thread_rec (ptid_t ptid, thread_disposition_type disposition) windows_nat::windows_process_info::thread_rec
(ptid_t ptid, thread_disposition_type disposition)
{ {
thread_info *thread = find_thread_ptid (ptid); thread_info *thread = find_thread_ptid (ptid);
if (thread == NULL) if (thread == NULL)
@ -182,7 +185,7 @@ child_add_thread (DWORD pid, DWORD tid, HANDLE h, void *tlb)
windows_thread_info *th; windows_thread_info *th;
ptid_t ptid = ptid_t (pid, tid, 0); 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; return th;
CORE_ADDR base = (CORE_ADDR) (uintptr_t) tlb; CORE_ADDR base = (CORE_ADDR) (uintptr_t) tlb;
@ -295,15 +298,15 @@ child_xfer_memory (CORE_ADDR memaddr, char *our, int len,
if (write) if (write)
{ {
success = WriteProcessMemory (current_process_handle, (LPVOID) addr, success = WriteProcessMemory (windows_process.handle, (LPVOID) addr,
(LPCVOID) our, len, &done); (LPCVOID) our, len, &done);
if (!success) if (!success)
lasterror = GetLastError (); lasterror = GetLastError ();
FlushInstructionCache (current_process_handle, (LPCVOID) addr, len); FlushInstructionCache (windows_process.handle, (LPCVOID) addr, len);
} }
else else
{ {
success = ReadProcessMemory (current_process_handle, (LPCVOID) addr, success = ReadProcessMemory (windows_process.handle, (LPCVOID) addr,
(LPVOID) our, len, &done); (LPVOID) our, len, &done);
if (!success) if (!success)
lasterror = GetLastError (); lasterror = GetLastError ();
@ -331,17 +334,17 @@ do_initial_child_stuff (HANDLE proch, DWORD pid, int attached)
{ {
struct process_info *proc; struct process_info *proc;
last_sig = GDB_SIGNAL_0; windows_process.last_sig = GDB_SIGNAL_0;
windows_process.handle = proch;
current_process_handle = proch; windows_process.id = pid;
current_process_id = pid; windows_process.main_thread_id = 0;
main_thread_id = 0;
soft_interrupt_requested = 0; soft_interrupt_requested = 0;
faked_breakpoint = 0; faked_breakpoint = 0;
open_process_used = true; open_process_used = true;
memset (&current_event, 0, sizeof (current_event)); memset (&windows_process.current_event, 0,
sizeof (windows_process.current_event));
#ifdef __x86_64__ #ifdef __x86_64__
BOOL wow64; BOOL wow64;
@ -417,7 +420,7 @@ do_initial_child_stuff (HANDLE proch, DWORD pid, int attached)
Rather than try to work around this sort of issue, it is much Rather than try to work around this sort of issue, it is much
simpler to just ignore DLL load/unload events during the startup simpler to just ignore DLL load/unload events during the startup
phase, and then process them all in one batch now. */ phase, and then process them all in one batch now. */
windows_add_all_dlls (); windows_process.add_all_dlls ();
child_initialization_done = 1; child_initialization_done = 1;
} }
@ -456,8 +459,8 @@ continue_one_thread (thread_info *thread, int thread_id)
static BOOL static BOOL
child_continue (DWORD continue_status, int thread_id) child_continue (DWORD continue_status, int thread_id)
{ {
desired_stop_thread_id = thread_id; windows_process.desired_stop_thread_id = thread_id;
if (matching_pending_stop (debug_threads)) if (windows_process.matching_pending_stop (debug_threads))
return TRUE; return TRUE;
/* The inferior will only continue after the ContinueDebugEvent /* The inferior will only continue after the ContinueDebugEvent
@ -476,8 +479,9 @@ static void
child_fetch_inferior_registers (struct regcache *regcache, int r) child_fetch_inferior_registers (struct regcache *regcache, int r)
{ {
int regno; int regno;
windows_thread_info *th = thread_rec (current_thread_ptid (), windows_thread_info *th
INVALIDATE_CONTEXT); = windows_process.thread_rec (current_thread_ptid (),
INVALIDATE_CONTEXT);
if (r == -1 || r > NUM_REGS) if (r == -1 || r > NUM_REGS)
child_fetch_inferior_registers (regcache, NUM_REGS); child_fetch_inferior_registers (regcache, NUM_REGS);
else else
@ -491,8 +495,9 @@ static void
child_store_inferior_registers (struct regcache *regcache, int r) child_store_inferior_registers (struct regcache *regcache, int r)
{ {
int regno; int regno;
windows_thread_info *th = thread_rec (current_thread_ptid (), windows_thread_info *th
INVALIDATE_CONTEXT); = windows_process.thread_rec (current_thread_ptid (),
INVALIDATE_CONTEXT);
if (r == -1 || r == 0 || r > NUM_REGS) if (r == -1 || r == 0 || r > NUM_REGS)
child_store_inferior_registers (regcache, NUM_REGS); child_store_inferior_registers (regcache, NUM_REGS);
else else
@ -671,12 +676,12 @@ win32_process_target::create_inferior (const char *program,
/* Wait till we are at 1st instruction in program, return new pid /* Wait till we are at 1st instruction in program, return new pid
(assuming success). */ (assuming success). */
cs.last_ptid = wait (ptid_t (current_process_id), &cs.last_status, 0); cs.last_ptid = wait (ptid_t (windows_process.id), &cs.last_status, 0);
/* Necessary for handle_v_kill. */ /* Necessary for handle_v_kill. */
signal_pid = current_process_id; signal_pid = windows_process.id;
return current_process_id; return windows_process.id;
} }
/* Attach to a running process. /* Attach to a running process.
@ -712,7 +717,8 @@ win32_process_target::attach (unsigned long pid)
/* See nat/windows-nat.h. */ /* See nat/windows-nat.h. */
int int
windows_nat::handle_output_debug_string (struct target_waitstatus *ourstatus) windows_nat::windows_process_info::handle_output_debug_string
(struct target_waitstatus *ourstatus)
{ {
#define READ_BUFFER_LEN 1024 #define READ_BUFFER_LEN 1024
CORE_ADDR addr; CORE_ADDR addr;
@ -762,12 +768,12 @@ win32_clear_inferiors (void)
{ {
if (open_process_used) if (open_process_used)
{ {
CloseHandle (current_process_handle); CloseHandle (windows_process.handle);
open_process_used = false; open_process_used = false;
} }
for_each_thread (delete_thread_info); for_each_thread (delete_thread_info);
siginfo_er.ExceptionCode = 0; windows_process.siginfo_er.ExceptionCode = 0;
clear_inferiors (); clear_inferiors ();
} }
@ -776,17 +782,19 @@ win32_clear_inferiors (void)
int int
win32_process_target::kill (process_info *process) win32_process_target::kill (process_info *process)
{ {
TerminateProcess (current_process_handle, 0); TerminateProcess (windows_process.handle, 0);
for (;;) for (;;)
{ {
if (!child_continue (DBG_CONTINUE, -1)) if (!child_continue (DBG_CONTINUE, -1))
break; break;
if (!wait_for_debug_event (&current_event, INFINITE)) if (!wait_for_debug_event (&windows_process.current_event, INFINITE))
break; break;
if (current_event.dwDebugEventCode == EXIT_PROCESS_DEBUG_EVENT) if (windows_process.current_event.dwDebugEventCode
== EXIT_PROCESS_DEBUG_EVENT)
break; break;
else if (current_event.dwDebugEventCode == OUTPUT_DEBUG_STRING_EVENT) else if (windows_process.current_event.dwDebugEventCode
handle_output_debug_string (nullptr); == OUTPUT_DEBUG_STRING_EVENT)
windows_process.handle_output_debug_string (nullptr);
} }
win32_clear_inferiors (); win32_clear_inferiors ();
@ -806,7 +814,7 @@ win32_process_target::detach (process_info *process)
resume.sig = 0; resume.sig = 0;
this->resume (&resume, 1); this->resume (&resume, 1);
if (!DebugActiveProcessStop (current_process_id)) if (!DebugActiveProcessStop (windows_process.id))
return -1; return -1;
DebugSetProcessKillOnExit (FALSE); DebugSetProcessKillOnExit (FALSE);
@ -866,7 +874,7 @@ win32_process_target::resume (thread_resume *resume_info, size_t n)
else else
/* Yes, we're ignoring resume_info[0].thread. It'd be tricky to make /* 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. */ 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 (resume_info[0].thread != minus_one_ptid)
{ {
@ -881,23 +889,24 @@ win32_process_target::resume (thread_resume *resume_info, size_t n)
if (sig != GDB_SIGNAL_0) 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", OUTMSG (("Cannot continue with signal %s here.\n",
gdb_signal_to_string (sig))); gdb_signal_to_string (sig)));
} }
else if (sig == last_sig) else if (sig == windows_process.last_sig)
continue_status = DBG_EXCEPTION_NOT_HANDLED; continue_status = DBG_EXCEPTION_NOT_HANDLED;
else else
OUTMSG (("Can only continue with received signal %s.\n", 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. */ /* Get context for the currently selected thread. */
ptid = debug_event_ptid (&current_event); ptid = debug_event_ptid (&windows_process.current_event);
th = thread_rec (ptid, DONT_INVALIDATE_CONTEXT); th = windows_process.thread_rec (ptid, DONT_INVALIDATE_CONTEXT);
if (th) if (th)
{ {
win32_prepare_to_resume (th); win32_prepare_to_resume (th);
@ -938,7 +947,8 @@ win32_process_target::resume (thread_resume *resume_info, size_t n)
/* See nat/windows-nat.h. */ /* See nat/windows-nat.h. */
void void
windows_nat::handle_load_dll (const char *name, LPVOID base) windows_nat::windows_process_info::handle_load_dll (const char *name,
LPVOID base)
{ {
CORE_ADDR load_addr = (CORE_ADDR) (uintptr_t) base; CORE_ADDR load_addr = (CORE_ADDR) (uintptr_t) base;
@ -992,7 +1002,7 @@ windows_nat::handle_load_dll (const char *name, LPVOID base)
/* See nat/windows-nat.h. */ /* See nat/windows-nat.h. */
void void
windows_nat::handle_unload_dll () windows_nat::windows_process_info::handle_unload_dll ()
{ {
CORE_ADDR load_addr = CORE_ADDR load_addr =
(CORE_ADDR) (uintptr_t) current_event.u.UnloadDll.lpBaseOfDll; (CORE_ADDR) (uintptr_t) current_event.u.UnloadDll.lpBaseOfDll;
@ -1019,10 +1029,11 @@ fake_breakpoint_event (void)
faked_breakpoint = 1; faked_breakpoint = 1;
memset (&current_event, 0, sizeof (current_event)); memset (&windows_process.current_event, 0,
current_event.dwThreadId = main_thread_id; sizeof (windows_process.current_event));
current_event.dwDebugEventCode = EXCEPTION_DEBUG_EVENT; windows_process.current_event.dwThreadId = windows_process.main_thread_id;
current_event.u.Exception.ExceptionRecord.ExceptionCode windows_process.current_event.dwDebugEventCode = EXCEPTION_DEBUG_EVENT;
windows_process.current_event.u.Exception.ExceptionRecord.ExceptionCode
= EXCEPTION_BREAKPOINT; = EXCEPTION_BREAKPOINT;
for_each_thread (suspend_one_thread); for_each_thread (suspend_one_thread);
@ -1031,7 +1042,8 @@ fake_breakpoint_event (void)
/* See nat/windows-nat.h. */ /* See nat/windows-nat.h. */
bool bool
windows_nat::handle_ms_vc_exception (const EXCEPTION_RECORD *rec) windows_nat::windows_process_info::handle_ms_vc_exception
(const EXCEPTION_RECORD *rec)
{ {
return false; return false;
} }
@ -1039,7 +1051,8 @@ windows_nat::handle_ms_vc_exception (const EXCEPTION_RECORD *rec)
/* See nat/windows-nat.h. */ /* See nat/windows-nat.h. */
bool bool
windows_nat::handle_access_violation (const EXCEPTION_RECORD *rec) windows_nat::windows_process_info::handle_access_violation
(const EXCEPTION_RECORD *rec)
{ {
return false; return false;
} }
@ -1054,14 +1067,15 @@ maybe_adjust_pc ()
struct regcache *regcache = get_thread_regcache (current_thread, 1); struct regcache *regcache = get_thread_regcache (current_thread, 1);
child_fetch_inferior_registers (regcache, -1); child_fetch_inferior_registers (regcache, -1);
windows_thread_info *th = thread_rec (current_thread_ptid (), windows_thread_info *th
DONT_INVALIDATE_CONTEXT); = windows_process.thread_rec (current_thread_ptid (),
DONT_INVALIDATE_CONTEXT);
th->stopped_at_software_breakpoint = false; th->stopped_at_software_breakpoint = false;
if (current_event.dwDebugEventCode == EXCEPTION_DEBUG_EVENT if (windows_process.current_event.dwDebugEventCode == EXCEPTION_DEBUG_EVENT
&& ((current_event.u.Exception.ExceptionRecord.ExceptionCode && ((windows_process.current_event.u.Exception.ExceptionRecord.ExceptionCode
== EXCEPTION_BREAKPOINT) == EXCEPTION_BREAKPOINT)
|| (current_event.u.Exception.ExceptionRecord.ExceptionCode || (windows_process.current_event.u.Exception.ExceptionRecord.ExceptionCode
== STATUS_WX86_BREAKPOINT)) == STATUS_WX86_BREAKPOINT))
&& child_initialization_done) && child_initialization_done)
{ {
@ -1080,13 +1094,15 @@ get_child_debug_event (DWORD *continue_status,
{ {
ptid_t ptid; ptid_t ptid;
last_sig = GDB_SIGNAL_0; windows_process.last_sig = GDB_SIGNAL_0;
ourstatus->set_spurious (); ourstatus->set_spurious ();
*continue_status = DBG_CONTINUE; *continue_status = DBG_CONTINUE;
/* Check if GDB sent us an interrupt request. */ /* Check if GDB sent us an interrupt request. */
check_remote_input_interrupt_request (); check_remote_input_interrupt_request ();
DEBUG_EVENT *current_event = &windows_process.current_event;
if (soft_interrupt_requested) if (soft_interrupt_requested)
{ {
soft_interrupt_requested = 0; soft_interrupt_requested = 0;
@ -1096,12 +1112,13 @@ get_child_debug_event (DWORD *continue_status,
attaching = 0; 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 ()) if (stop.has_value ())
{ {
*ourstatus = stop->status; *ourstatus = stop->status;
current_event = stop->event; windows_process.current_event = stop->event;
ptid = debug_event_ptid (&current_event); ptid = debug_event_ptid (&windows_process.current_event);
switch_to_thread (find_thread_ptid (ptid)); switch_to_thread (find_thread_ptid (ptid));
return 1; return 1;
} }
@ -1109,7 +1126,7 @@ get_child_debug_event (DWORD *continue_status,
/* Keep the wait time low enough for comfortable remote /* Keep the wait time low enough for comfortable remote
interruption, but high enough so gdbserver doesn't become a interruption, but high enough so gdbserver doesn't become a
bottleneck. */ bottleneck. */
if (!wait_for_debug_event (&current_event, 250)) if (!wait_for_debug_event (&windows_process.current_event, 250))
{ {
DWORD e = GetLastError(); DWORD e = GetLastError();
@ -1129,28 +1146,28 @@ get_child_debug_event (DWORD *continue_status,
gotevent: gotevent:
switch (current_event.dwDebugEventCode) switch (current_event->dwDebugEventCode)
{ {
case CREATE_THREAD_DEBUG_EVENT: case CREATE_THREAD_DEBUG_EVENT:
OUTMSG2 (("gdbserver: kernel event CREATE_THREAD_DEBUG_EVENT " OUTMSG2 (("gdbserver: kernel event CREATE_THREAD_DEBUG_EVENT "
"for pid=%u tid=%x)\n", "for pid=%u tid=%x)\n",
(unsigned) current_event.dwProcessId, (unsigned) current_event->dwProcessId,
(unsigned) current_event.dwThreadId)); (unsigned) current_event->dwThreadId));
/* Record the existence of this thread. */ /* Record the existence of this thread. */
child_add_thread (current_event.dwProcessId, child_add_thread (current_event->dwProcessId,
current_event.dwThreadId, current_event->dwThreadId,
current_event.u.CreateThread.hThread, current_event->u.CreateThread.hThread,
current_event.u.CreateThread.lpThreadLocalBase); current_event->u.CreateThread.lpThreadLocalBase);
break; break;
case EXIT_THREAD_DEBUG_EVENT: case EXIT_THREAD_DEBUG_EVENT:
OUTMSG2 (("gdbserver: kernel event EXIT_THREAD_DEBUG_EVENT " OUTMSG2 (("gdbserver: kernel event EXIT_THREAD_DEBUG_EVENT "
"for pid=%u tid=%x\n", "for pid=%u tid=%x\n",
(unsigned) current_event.dwProcessId, (unsigned) current_event->dwProcessId,
(unsigned) current_event.dwThreadId)); (unsigned) current_event->dwThreadId));
child_delete_thread (current_event.dwProcessId, child_delete_thread (current_event->dwProcessId,
current_event.dwThreadId); current_event->dwThreadId);
switch_to_thread (get_first_thread ()); switch_to_thread (get_first_thread ());
return 1; return 1;
@ -1158,33 +1175,33 @@ get_child_debug_event (DWORD *continue_status,
case CREATE_PROCESS_DEBUG_EVENT: case CREATE_PROCESS_DEBUG_EVENT:
OUTMSG2 (("gdbserver: kernel event CREATE_PROCESS_DEBUG_EVENT " OUTMSG2 (("gdbserver: kernel event CREATE_PROCESS_DEBUG_EVENT "
"for pid=%u tid=%x\n", "for pid=%u tid=%x\n",
(unsigned) current_event.dwProcessId, (unsigned) current_event->dwProcessId,
(unsigned) current_event.dwThreadId)); (unsigned) current_event->dwThreadId));
CloseHandle (current_event.u.CreateProcessInfo.hFile); CloseHandle (current_event->u.CreateProcessInfo.hFile);
if (open_process_used) if (open_process_used)
{ {
CloseHandle (current_process_handle); CloseHandle (windows_process.handle);
open_process_used = false; open_process_used = false;
} }
current_process_handle = current_event.u.CreateProcessInfo.hProcess; windows_process.handle = current_event->u.CreateProcessInfo.hProcess;
main_thread_id = current_event.dwThreadId; windows_process.main_thread_id = current_event->dwThreadId;
/* Add the main thread. */ /* Add the main thread. */
child_add_thread (current_event.dwProcessId, child_add_thread (current_event->dwProcessId,
main_thread_id, windows_process.main_thread_id,
current_event.u.CreateProcessInfo.hThread, current_event->u.CreateProcessInfo.hThread,
current_event.u.CreateProcessInfo.lpThreadLocalBase); current_event->u.CreateProcessInfo.lpThreadLocalBase);
break; break;
case EXIT_PROCESS_DEBUG_EVENT: case EXIT_PROCESS_DEBUG_EVENT:
OUTMSG2 (("gdbserver: kernel event EXIT_PROCESS_DEBUG_EVENT " OUTMSG2 (("gdbserver: kernel event EXIT_PROCESS_DEBUG_EVENT "
"for pid=%u tid=%x\n", "for pid=%u tid=%x\n",
(unsigned) current_event.dwProcessId, (unsigned) current_event->dwProcessId,
(unsigned) current_event.dwThreadId)); (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 /* If the exit status looks like a fatal exception, but we
don't recognize the exception's code, make the original don't recognize the exception's code, make the original
exit status value available, to avoid losing information. */ exit status value available, to avoid losing information. */
@ -1195,18 +1212,18 @@ get_child_debug_event (DWORD *continue_status,
else else
ourstatus->set_signalled (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; break;
case LOAD_DLL_DEBUG_EVENT: case LOAD_DLL_DEBUG_EVENT:
OUTMSG2 (("gdbserver: kernel event LOAD_DLL_DEBUG_EVENT " OUTMSG2 (("gdbserver: kernel event LOAD_DLL_DEBUG_EVENT "
"for pid=%u tid=%x\n", "for pid=%u tid=%x\n",
(unsigned) current_event.dwProcessId, (unsigned) current_event->dwProcessId,
(unsigned) current_event.dwThreadId)); (unsigned) current_event->dwThreadId));
CloseHandle (current_event.u.LoadDll.hFile); CloseHandle (current_event->u.LoadDll.hFile);
if (! child_initialization_done) if (! child_initialization_done)
break; break;
dll_loaded_event (); windows_process.dll_loaded_event ();
ourstatus->set_loaded (); ourstatus->set_loaded ();
break; break;
@ -1214,20 +1231,20 @@ get_child_debug_event (DWORD *continue_status,
case UNLOAD_DLL_DEBUG_EVENT: case UNLOAD_DLL_DEBUG_EVENT:
OUTMSG2 (("gdbserver: kernel event UNLOAD_DLL_DEBUG_EVENT " OUTMSG2 (("gdbserver: kernel event UNLOAD_DLL_DEBUG_EVENT "
"for pid=%u tid=%x\n", "for pid=%u tid=%x\n",
(unsigned) current_event.dwProcessId, (unsigned) current_event->dwProcessId,
(unsigned) current_event.dwThreadId)); (unsigned) current_event->dwThreadId));
if (! child_initialization_done) if (! child_initialization_done)
break; break;
handle_unload_dll (); windows_process.handle_unload_dll ();
ourstatus->set_loaded (); ourstatus->set_loaded ();
break; break;
case EXCEPTION_DEBUG_EVENT: case EXCEPTION_DEBUG_EVENT:
OUTMSG2 (("gdbserver: kernel event EXCEPTION_DEBUG_EVENT " OUTMSG2 (("gdbserver: kernel event EXCEPTION_DEBUG_EVENT "
"for pid=%u tid=%x\n", "for pid=%u tid=%x\n",
(unsigned) current_event.dwProcessId, (unsigned) current_event->dwProcessId,
(unsigned) current_event.dwThreadId)); (unsigned) current_event->dwThreadId));
if (handle_exception (ourstatus, debug_threads) if (windows_process.handle_exception (ourstatus, debug_threads)
== HANDLE_EXCEPTION_UNHANDLED) == HANDLE_EXCEPTION_UNHANDLED)
*continue_status = DBG_EXCEPTION_NOT_HANDLED; *continue_status = DBG_EXCEPTION_NOT_HANDLED;
break; break;
@ -1236,31 +1253,33 @@ get_child_debug_event (DWORD *continue_status,
/* A message from the kernel (or Cygwin). */ /* A message from the kernel (or Cygwin). */
OUTMSG2 (("gdbserver: kernel event OUTPUT_DEBUG_STRING_EVENT " OUTMSG2 (("gdbserver: kernel event OUTPUT_DEBUG_STRING_EVENT "
"for pid=%u tid=%x\n", "for pid=%u tid=%x\n",
(unsigned) current_event.dwProcessId, (unsigned) current_event->dwProcessId,
(unsigned) current_event.dwThreadId)); (unsigned) current_event->dwThreadId));
handle_output_debug_string (nullptr); windows_process.handle_output_debug_string (nullptr);
break; break;
default: default:
OUTMSG2 (("gdbserver: kernel event unknown " OUTMSG2 (("gdbserver: kernel event unknown "
"for pid=%u tid=%x code=%x\n", "for pid=%u tid=%x code=%x\n",
(unsigned) current_event.dwProcessId, (unsigned) current_event->dwProcessId,
(unsigned) current_event.dwThreadId, (unsigned) current_event->dwThreadId,
(unsigned) current_event.dwDebugEventCode)); (unsigned) current_event->dwDebugEventCode));
break; break;
} }
ptid = debug_event_ptid (&current_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 stop. See the comment by the definition of
"pending_stops" for details on why this is needed. */ "pending_stops" for details on why this is needed. */
OUTMSG2 (("get_windows_debug_event - " OUTMSG2 (("get_windows_debug_event - "
"unexpected stop in 0x%lx (expecting 0x%x)\n", "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 (); maybe_adjust_pc ();
pending_stops.push_back ({(DWORD) ptid.lwp (), *ourstatus, current_event}); windows_process.pending_stops.push_back
({(DWORD) ptid.lwp (), *ourstatus, *current_event});
ourstatus->set_spurious (); ourstatus->set_spurious ();
} }
else else
@ -1284,7 +1303,7 @@ win32_process_target::wait (ptid_t ptid, target_waitstatus *ourstatus,
fails). Report it now. */ fails). Report it now. */
*ourstatus = cached_status; *ourstatus = cached_status;
cached_status.set_ignore (); cached_status.set_ignore ();
return debug_event_ptid (&current_event); return debug_event_ptid (&windows_process.current_event);
} }
while (1) while (1)
@ -1299,7 +1318,7 @@ win32_process_target::wait (ptid_t ptid, target_waitstatus *ourstatus,
OUTMSG2 (("Child exited with retcode = %x\n", OUTMSG2 (("Child exited with retcode = %x\n",
ourstatus->exit_status ())); ourstatus->exit_status ()));
win32_clear_inferiors (); win32_clear_inferiors ();
return ptid_t (current_event.dwProcessId); return ptid_t (windows_process.current_event.dwProcessId);
case TARGET_WAITKIND_STOPPED: case TARGET_WAITKIND_STOPPED:
case TARGET_WAITKIND_SIGNALLED: case TARGET_WAITKIND_SIGNALLED:
case TARGET_WAITKIND_LOADED: case TARGET_WAITKIND_LOADED:
@ -1307,7 +1326,7 @@ win32_process_target::wait (ptid_t ptid, target_waitstatus *ourstatus,
OUTMSG2 (("Child Stopped with signal = %d \n", OUTMSG2 (("Child Stopped with signal = %d \n",
ourstatus->sig ())); ourstatus->sig ()));
maybe_adjust_pc (); maybe_adjust_pc ();
return debug_event_ptid (&current_event); return debug_event_ptid (&windows_process.current_event);
} }
default: default:
OUTMSG (("Ignoring unknown internal event, %d\n", OUTMSG (("Ignoring unknown internal event, %d\n",
@ -1315,7 +1334,8 @@ win32_process_target::wait (ptid_t ptid, target_waitstatus *ourstatus,
/* fall-through */ /* fall-through */
case TARGET_WAITKIND_SPURIOUS: case TARGET_WAITKIND_SPURIOUS:
/* do nothing, just continue */ /* do nothing, just continue */
child_continue (continue_status, desired_stop_thread_id); child_continue (continue_status,
windows_process.desired_stop_thread_id);
break; break;
} }
} }
@ -1362,7 +1382,7 @@ win32_process_target::write_memory (CORE_ADDR memaddr,
void void
win32_process_target::request_interrupt () win32_process_target::request_interrupt ()
{ {
if (GenerateConsoleCtrlEvent (CTRL_BREAK_EVENT, current_process_id)) if (GenerateConsoleCtrlEvent (CTRL_BREAK_EVENT, windows_process.id))
return; return;
/* GenerateConsoleCtrlEvent can fail if process id being debugged is /* GenerateConsoleCtrlEvent can fail if process id being debugged is
@ -1370,7 +1390,7 @@ win32_process_target::request_interrupt ()
Fallback to XP/Vista 'DebugBreakProcess', which generates a Fallback to XP/Vista 'DebugBreakProcess', which generates a
breakpoint exception in the interior process. */ breakpoint exception in the interior process. */
if (DebugBreakProcess (current_process_handle)) if (DebugBreakProcess (windows_process.handle))
return; return;
/* Last resort, suspend all threads manually. */ /* Last resort, suspend all threads manually. */
@ -1397,14 +1417,14 @@ win32_process_target::qxfer_siginfo (const char *annex,
unsigned const char *writebuf, unsigned const char *writebuf,
CORE_ADDR offset, int len) CORE_ADDR offset, int len)
{ {
if (siginfo_er.ExceptionCode == 0) if (windows_process.siginfo_er.ExceptionCode == 0)
return -1; return -1;
if (readbuf == nullptr) if (readbuf == nullptr)
return -1; return -1;
char *buf = (char *) &siginfo_er; char *buf = (char *) &windows_process.siginfo_er;
size_t bufsize = sizeof (siginfo_er); size_t bufsize = sizeof (windows_process.siginfo_er);
#ifdef __x86_64__ #ifdef __x86_64__
EXCEPTION_RECORD32 er32; EXCEPTION_RECORD32 er32;
@ -1447,7 +1467,7 @@ int
win32_process_target::get_tib_address (ptid_t ptid, CORE_ADDR *addr) win32_process_target::get_tib_address (ptid_t ptid, CORE_ADDR *addr)
{ {
windows_thread_info *th; windows_thread_info *th;
th = thread_rec (ptid, DONT_INVALIDATE_CONTEXT); th = windows_process.thread_rec (ptid, DONT_INVALIDATE_CONTEXT);
if (th == NULL) if (th == NULL)
return 0; return 0;
if (addr != NULL) if (addr != NULL)
@ -1467,8 +1487,9 @@ win32_process_target::sw_breakpoint_from_kind (int kind, int *size)
bool bool
win32_process_target::stopped_by_sw_breakpoint () win32_process_target::stopped_by_sw_breakpoint ()
{ {
windows_thread_info *th = thread_rec (current_thread_ptid (), windows_thread_info *th
DONT_INVALIDATE_CONTEXT); = windows_process.thread_rec (current_thread_ptid (),
DONT_INVALIDATE_CONTEXT);
return th == nullptr ? false : th->stopped_at_software_breakpoint; return th == nullptr ? false : th->stopped_at_software_breakpoint;
} }