X-Git-Url: http://git.ipfire.org/?a=blobdiff_plain;f=gdbserver%2Fwin32-low.cc;h=756507709d81971ef59fcaddc9768a37679ca1d4;hb=213516ef315dc1785e4990ef0fc011abedb38cc0;hp=9c715fea3622741292fb7b29703f3756e3a56107;hpb=c23c939174445a65de521041509b038f5839a742;p=thirdparty%2Fbinutils-gdb.git diff --git a/gdbserver/win32-low.cc b/gdbserver/win32-low.cc index 9c715fea362..756507709d8 100644 --- a/gdbserver/win32-low.cc +++ b/gdbserver/win32-low.cc @@ -1,5 +1,5 @@ /* Low level interface to Windows debugging, for gdbserver. - Copyright (C) 2006-2020 Free Software Foundation, Inc. + Copyright (C) 2006-2023 Free Software Foundation, Inc. Contributed by Leo Zayas. Based on "win32-nat.c" from GDB. @@ -20,7 +20,7 @@ #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" @@ -36,6 +36,11 @@ #include "gdbsupport/common-inferior.h" #include "gdbsupport/gdb_wait.h" +using namespace windows_nat; + +/* See win32-low.h. */ +gdbserver_windows_process windows_process; + #ifndef USE_WIN32API #include #endif @@ -56,57 +61,15 @@ #define _T(x) TEXT (x) #endif -#ifndef COUNTOF -#define COUNTOF(STR) (sizeof (STR) / sizeof ((STR)[0])) -#endif - -#ifdef _WIN32_WCE -# define GETPROCADDRESS(DLL, PROC) \ - ((winapi_ ## PROC) GetProcAddress (DLL, TEXT (#PROC))) -#else -# define GETPROCADDRESS(DLL, PROC) \ - ((winapi_ ## PROC) GetProcAddress (DLL, #PROC)) -#endif - int using_threads = 1; -/* Globals. */ -static int attaching = 0; -static HANDLE current_process_handle = NULL; -static DWORD current_process_id = 0; -static DWORD main_thread_id = 0; -static EXCEPTION_RECORD siginfo_er; /* Contents of $_siginfo */ -static enum gdb_signal last_sig = GDB_SIGNAL_0; - -/* The current debug event from WaitForDebugEvent. */ -static DEBUG_EVENT current_event; - -/* A status that hasn't been reported to the core yet, and so - win32_wait should return it next, instead of fetching the next - 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; - const struct target_desc *win32_tdesc; - -#define NUM_REGS (the_low_target.num_regs) - -typedef BOOL (WINAPI *winapi_DebugActiveProcessStop) (DWORD dwProcessId); -typedef BOOL (WINAPI *winapi_DebugSetProcessKillOnExit) (BOOL KillOnExit); -typedef BOOL (WINAPI *winapi_DebugBreakProcess) (HANDLE); -typedef BOOL (WINAPI *winapi_GenerateConsoleCtrlEvent) (DWORD, DWORD); - -#ifndef _WIN32_WCE -static void win32_add_all_dlls (void); +#ifdef __x86_64__ +const struct target_desc *wow64_win32_tdesc; #endif +#define NUM_REGS (the_low_target.num_regs ()) + /* Get the thread ID from the current selected inferior (the current thread). */ static ptid_t @@ -125,32 +88,26 @@ debug_event_ptid (DEBUG_EVENT *event) /* Get the thread context of the thread associated with TH. */ static void -win32_get_thread_context (win32_thread_info *th) +win32_get_thread_context (windows_thread_info *th) { - memset (&th->context, 0, sizeof (CONTEXT)); - (*the_low_target.get_thread_context) (th); -#ifdef _WIN32_WCE - memcpy (&th->base_context, &th->context, sizeof (CONTEXT)); +#ifdef __x86_64__ + if (windows_process.wow64_process) + memset (&th->wow64_context, 0, sizeof (WOW64_CONTEXT)); + else #endif + memset (&th->context, 0, sizeof (CONTEXT)); + (*the_low_target.get_thread_context) (th); } /* Set the thread context of the thread associated with TH. */ static void -win32_set_thread_context (win32_thread_info *th) +win32_set_thread_context (windows_thread_info *th) { -#ifdef _WIN32_WCE - /* Calling SuspendThread on a thread that is running kernel code - will report that the suspending was successful, but in fact, that - will often not be true. In those cases, the context returned by - GetThreadContext will not be correct by the time the thread - stops, hence we can't set that context back into the thread when - resuming - it will most likely crash the inferior. - Unfortunately, there is no way to know when the thread will - really stop. To work around it, we'll only write the context - back to the thread when either the user or GDB explicitly change - it between stopping and resuming. */ - if (memcmp (&th->context, &th->base_context, sizeof (CONTEXT)) != 0) +#ifdef __x86_64__ + if (windows_process.wow64_process) + Wow64SetThreadContext (th->h, &th->wow64_context); + else #endif SetThreadContext (th->h, &th->context); } @@ -158,7 +115,7 @@ win32_set_thread_context (win32_thread_info *th) /* Set the thread context of the thread associated with TH. */ static void -win32_prepare_to_resume (win32_thread_info *th) +win32_prepare_to_resume (windows_thread_info *th) { if (the_low_target.prepare_to_resume != NULL) (*the_low_target.prepare_to_resume) (th); @@ -167,55 +124,56 @@ win32_prepare_to_resume (win32_thread_info *th) /* See win32-low.h. */ void -win32_require_context (win32_thread_info *th) +win32_require_context (windows_thread_info *th) { - if (th->context.ContextFlags == 0) + DWORD context_flags; +#ifdef __x86_64__ + if (windows_process.wow64_process) + context_flags = th->wow64_context.ContextFlags; + else +#endif + context_flags = th->context.ContextFlags; + if (context_flags == 0) { - if (!th->suspended) - { - if (SuspendThread (th->h) == (DWORD) -1) - { - DWORD err = GetLastError (); - OUTMSG (("warning: SuspendThread failed in thread_rec, " - "(error %d): %s\n", (int) err, strwinerror (err))); - } - else - th->suspended = 1; - } - + th->suspend (); win32_get_thread_context (th); } } -/* Find a thread record given a thread id. If GET_CONTEXT is set then - also retrieve the context for this thread. */ -static win32_thread_info * -thread_rec (ptid_t ptid, int get_context) +/* See nat/windows-nat.h. */ + +windows_thread_info * +gdbserver_windows_process::thread_rec + (ptid_t ptid, thread_disposition_type disposition) { thread_info *thread = find_thread_ptid (ptid); if (thread == NULL) return NULL; - win32_thread_info *th = (win32_thread_info *) thread_target_data (thread); - if (get_context) + windows_thread_info *th = (windows_thread_info *) thread_target_data (thread); + if (disposition != DONT_INVALIDATE_CONTEXT) win32_require_context (th); return th; } /* Add a thread to the thread list. */ -static win32_thread_info * +static windows_thread_info * child_add_thread (DWORD pid, DWORD tid, HANDLE h, void *tlb) { - win32_thread_info *th; + windows_thread_info *th; ptid_t ptid = ptid_t (pid, tid, 0); - if ((th = thread_rec (ptid, FALSE))) + if ((th = windows_process.thread_rec (ptid, DONT_INVALIDATE_CONTEXT))) return th; - th = XCNEW (win32_thread_info); - th->tid = tid; - th->h = h; - th->thread_local_base = (CORE_ADDR) (uintptr_t) tlb; + CORE_ADDR base = (CORE_ADDR) (uintptr_t) tlb; +#ifdef __x86_64__ + /* For WOW64 processes, this is actually the pointer to the 64bit TIB, + and the 32bit TIB is exactly 2 pages after it. */ + if (windows_process.wow64_process) + base += 2 * 4096; /* page size = 4096 */ +#endif + th = new windows_thread_info (tid, h, base); add_thread (ptid, th); @@ -229,11 +187,10 @@ child_add_thread (DWORD pid, DWORD tid, HANDLE h, void *tlb) static void delete_thread_info (thread_info *thread) { - win32_thread_info *th = (win32_thread_info *) thread_target_data (thread); + windows_thread_info *th = (windows_thread_info *) thread_target_data (thread); remove_thread (thread); - CloseHandle (th->h); - free (th); + delete th; } /* Delete a thread from the list of threads. */ @@ -257,15 +214,18 @@ child_delete_thread (DWORD pid, DWORD tid) bool win32_process_target::supports_z_point_type (char z_type) { - return (the_low_target.supports_z_point_type != NULL - && the_low_target.supports_z_point_type (z_type)); + return (z_type == Z_PACKET_SW_BP + || (the_low_target.supports_z_point_type != NULL + && the_low_target.supports_z_point_type (z_type))); } int win32_process_target::insert_point (enum raw_bkpt_type type, CORE_ADDR addr, int size, raw_breakpoint *bp) { - if (the_low_target.insert_point != NULL) + if (type == raw_bkpt_type_sw) + return insert_memory_breakpoint (bp); + else if (the_low_target.insert_point != NULL) return the_low_target.insert_point (type, addr, size, bp); else /* Unsupported (see target.h). */ @@ -276,7 +236,9 @@ int win32_process_target::remove_point (enum raw_bkpt_type type, CORE_ADDR addr, int size, raw_breakpoint *bp) { - if (the_low_target.remove_point != NULL) + if (type == raw_bkpt_type_sw) + return remove_memory_breakpoint (bp); + else if (the_low_target.remove_point != NULL) return the_low_target.remove_point (type, addr, size, bp); else /* Unsupported (see target.h). */ @@ -314,15 +276,15 @@ child_xfer_memory (CORE_ADDR memaddr, char *our, int len, 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 (); @@ -341,35 +303,55 @@ child_init_thread_list (void) 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; + windows_process.last_sig = GDB_SIGNAL_0; + windows_process.handle = proch; + windows_process.main_thread_id = 0; - current_process_handle = proch; - current_process_id = pid; - main_thread_id = 0; + windows_process.soft_interrupt_requested = 0; + windows_process.faked_breakpoint = 0; + windows_process.open_process_used = true; - soft_interrupt_requested = 0; - faked_breakpoint = 0; + memset (&windows_process.current_event, 0, + sizeof (windows_process.current_event)); - memset (¤t_event, 0, sizeof (current_event)); +#ifdef __x86_64__ + BOOL wow64; + if (!IsWow64Process (proch, &wow64)) + { + DWORD err = GetLastError (); + error ("Check if WOW64 process failed (error %d): %s\n", + (int) err, strwinerror (err)); + } + windows_process.wow64_process = wow64; + + if (windows_process.wow64_process + && (Wow64GetThreadContext == nullptr + || Wow64SetThreadContext == nullptr)) + error ("WOW64 debugging is not supported on this system.\n"); + + windows_process.ignore_first_breakpoint + = !attached && windows_process.wow64_process; +#endif proc = add_process (pid, attached); - proc->tdesc = win32_tdesc; +#ifdef __x86_64__ + 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. */ @@ -377,12 +359,12 @@ do_initial_child_stuff (HANDLE proch, DWORD pid, int attached) { struct target_waitstatus status; - the_target->pt->wait (minus_one_ptid, &status, 0); + the_target->wait (minus_one_ptid, &status, 0); /* Note win32_wait doesn't return thread events. */ - if (status.kind != TARGET_WAITKIND_LOADED) + if (status.kind () != TARGET_WAITKIND_LOADED) { - cached_status = status; + windows_process.cached_status = status; break; } @@ -393,11 +375,10 @@ do_initial_child_stuff (HANDLE proch, DWORD pid, int attached) resume.kind = resume_continue; resume.sig = 0; - the_target->pt->resume (&resume, 1); + the_target->resume (&resume, 1); } } -#ifndef _WIN32_WCE /* Now that the inferior has been started and all DLLs have been mapped, we can iterate over all DLLs and load them in. @@ -413,10 +394,9 @@ do_initial_child_stuff (HANDLE proch, DWORD pid, int attached) Rather than try to work around this sort of issue, it is much simpler to just ignore DLL load/unload events during the startup phase, and then process them all in one batch now. */ - win32_add_all_dlls (); -#endif + windows_process.add_all_dlls (); - child_initialization_done = 1; + windows_process.child_initialization_done = 1; } /* Resume all artificially suspended threads if we are continuing @@ -424,7 +404,7 @@ do_initial_child_stuff (HANDLE proch, DWORD pid, int attached) static void continue_one_thread (thread_info *thread, int thread_id) { - win32_thread_info *th = (win32_thread_info *) thread_target_data (thread); + windows_thread_info *th = (windows_thread_info *) thread_target_data (thread); if (thread_id == -1 || thread_id == th->tid) { @@ -432,19 +412,20 @@ continue_one_thread (thread_info *thread, int thread_id) if (th->suspended) { - if (th->context.ContextFlags) + DWORD *context_flags; +#ifdef __x86_64__ + if (windows_process.wow64_process) + context_flags = &th->wow64_context.ContextFlags; + else +#endif + context_flags = &th->context.ContextFlags; + if (*context_flags) { win32_set_thread_context (th); - th->context.ContextFlags = 0; + *context_flags = 0; } - if (ResumeThread (th->h) == (DWORD) -1) - { - DWORD err = GetLastError (); - OUTMSG (("warning: ResumeThread failed in continue_one_thread, " - "(error %d): %s\n", (int) err, strwinerror (err))); - } - th->suspended = 0; + th->resume (); } } } @@ -452,20 +433,19 @@ continue_one_thread (thread_info *thread, int thread_id) static BOOL child_continue (DWORD continue_status, int thread_id) { + 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 call. */ for_each_thread ([&] (thread_info *thread) { continue_one_thread (thread, thread_id); }); - faked_breakpoint = 0; + windows_process.faked_breakpoint = 0; - if (!ContinueDebugEvent (current_event.dwProcessId, - current_event.dwThreadId, - continue_status)) - return FALSE; - - return TRUE; + return continue_last_debug_event (continue_status, debug_threads); } /* Fetch register(s) from the current thread context. */ @@ -473,7 +453,9 @@ static void child_fetch_inferior_registers (struct regcache *regcache, int r) { int regno; - win32_thread_info *th = thread_rec (current_thread_ptid (), TRUE); + windows_thread_info *th + = windows_process.thread_rec (current_thread_ptid (), + INVALIDATE_CONTEXT); if (r == -1 || r > NUM_REGS) child_fetch_inferior_registers (regcache, NUM_REGS); else @@ -487,7 +469,9 @@ static void child_store_inferior_registers (struct regcache *regcache, int r) { int regno; - win32_thread_info *th = thread_rec (current_thread_ptid (), TRUE); + windows_thread_info *th + = 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 @@ -495,132 +479,34 @@ child_store_inferior_registers (struct regcache *regcache, int r) (*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; proglen = strlen (program) + 1; argslen = strlen (args) + proglen; -#ifdef _WIN32_WCE - wchar_t *p, *wprogram, *wargs, *wcwd = NULL; - - wprogram = (wchar_t *) alloca (proglen * sizeof (wchar_t)); - mbstowcs (wprogram, program, proglen); - - for (p = wprogram; *p; ++p) - if (L'/' == *p) - *p = L'\\'; - - wargs = alloca ((argslen + 1) * sizeof (wchar_t)); - wcscpy (wargs, wprogram); - wcscat (wargs, L" "); - mbstowcs (wargs + proglen, args, argslen + 1 - proglen); - - if (inferior_cwd != NULL) - { - std::string expanded_infcwd = gdb_tilde_expand (inferior_cwd); - std::replace (expanded_infcwd.begin (), expanded_infcwd.end (), - '/', '\\'); - wcwd = alloca ((expanded_infcwd.size () + 1) * sizeof (wchar_t)); - if (mbstowcs (wcwd, expanded_infcwd.c_str (), - expanded_infcwd.size () + 1) == NULL) - { - error (_("\ -Could not convert the expanded inferior cwd to wide-char.")); - } - } - - ret = CreateProcessW (wprogram, /* image name */ - wargs, /* command line */ - NULL, /* security, not supported */ - NULL, /* thread, not supported */ - FALSE, /* inherit handles, not supported */ - flags, /* start flags */ - NULL, /* environment, not supported */ - wcwd, /* current directory */ - NULL, /* start info, not supported */ - pi); /* proc info */ -#else STARTUPINFOA si = { sizeof (STARTUPINFOA) }; char *program_and_args = (char *) alloca (argslen + 1); 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 */ -#endif return ret; } @@ -643,11 +529,11 @@ win32_process_target::create_inferior (const char *program, DWORD flags; PROCESS_INFORMATION pi; DWORD err; - std::string str_program_args = stringify_argv (program_args); + std::string str_program_args = construct_inferior_arguments (program_args); 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"); @@ -701,23 +587,18 @@ win32_process_target::create_inferior (const char *program, OUTMSG2 (("Process created: %s %s\n", program, (char *) args)); } -#ifndef _WIN32_WCE - /* On Windows CE this handle can't be closed. The OS reuses - it in the debug events, while the 9x/NT versions of Windows - probably use a DuplicateHandle'd one. */ CloseHandle (pi.hThread); -#endif do_initial_child_stuff (pi.hProcess, pi.dwProcessId, 0); /* 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. @@ -727,25 +608,17 @@ int win32_process_target::attach (unsigned long pid) { HANDLE h; - winapi_DebugSetProcessKillOnExit DebugSetProcessKillOnExit = NULL; DWORD err; -#ifdef _WIN32_WCE - HMODULE dll = GetModuleHandle (_T("COREDLL.DLL")); -#else - HMODULE dll = GetModuleHandle (_T("KERNEL32.DLL")); -#endif - DebugSetProcessKillOnExit = GETPROCADDRESS (dll, DebugSetProcessKillOnExit); 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; } @@ -758,9 +631,11 @@ win32_process_target::attach (unsigned long pid) (int) err, strwinerror (err)); } -/* Handle OUTPUT_DEBUG_STRING_EVENT from child process. */ -static void -handle_output_debug_string (void) +/* See nat/windows-nat.h. */ + +int +gdbserver_windows_process::handle_output_debug_string + (struct target_waitstatus *ourstatus) { #define READ_BUFFER_LEN 1024 CORE_ADDR addr; @@ -768,7 +643,7 @@ handle_output_debug_string (void) DWORD nbytes = current_event.u.DebugString.nDebugStringLength; if (nbytes == 0) - return; + return 0; if (nbytes > READ_BUFFER_LEN) nbytes = READ_BUFFER_LEN; @@ -781,13 +656,13 @@ handle_output_debug_string (void) in Unicode. */ WCHAR buffer[(READ_BUFFER_LEN + 1) / sizeof (WCHAR)] = { 0 }; if (read_inferior_memory (addr, (unsigned char *) buffer, nbytes) != 0) - return; + return 0; wcstombs (s, buffer, (nbytes + 1) / sizeof (WCHAR)); } else { if (read_inferior_memory (addr, (unsigned char *) s, nbytes) != 0) - return; + return 0; } if (!startswith (s, "cYg")) @@ -795,22 +670,27 @@ handle_output_debug_string (void) if (!server_waiting) { OUTMSG2(("%s", s)); - return; + return 0; } monitor_output (s); } #undef READ_BUFFER_LEN + + return 0; } static void win32_clear_inferiors (void) { - if (current_process_handle != NULL) - CloseHandle (current_process_handle); + if (windows_process.open_process_used) + { + 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 (); } @@ -819,17 +699,19 @@ win32_clear_inferiors (void) 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 (!WaitForDebugEvent (¤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 (); + else if (windows_process.current_event.dwDebugEventCode + == OUTPUT_DEBUG_STRING_EVENT) + windows_process.handle_output_debug_string (nullptr); } win32_clear_inferiors (); @@ -843,29 +725,13 @@ win32_process_target::kill (process_info *process) int win32_process_target::detach (process_info *process) { - winapi_DebugActiveProcessStop DebugActiveProcessStop = NULL; - winapi_DebugSetProcessKillOnExit DebugSetProcessKillOnExit = NULL; -#ifdef _WIN32_WCE - HMODULE dll = GetModuleHandle (_T("COREDLL.DLL")); -#else - HMODULE dll = GetModuleHandle (_T("KERNEL32.DLL")); -#endif - DebugActiveProcessStop = GETPROCADDRESS (dll, DebugActiveProcessStop); - DebugSetProcessKillOnExit = GETPROCADDRESS (dll, DebugSetProcessKillOnExit); - - if (DebugSetProcessKillOnExit == NULL - || DebugActiveProcessStop == NULL) - return -1; + struct thread_resume resume; + resume.thread = minus_one_ptid; + resume.kind = resume_continue; + resume.sig = 0; + 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); @@ -911,7 +777,7 @@ win32_process_target::resume (thread_resume *resume_info, size_t n) DWORD tid; enum gdb_signal sig; int step; - win32_thread_info *th; + windows_thread_info *th; DWORD continue_status = DBG_CONTINUE; ptid_t ptid; @@ -925,7 +791,7 @@ win32_process_target::resume (thread_resume *resume_info, size_t n) 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) { @@ -940,28 +806,36 @@ win32_process_target::resume (thread_resume *resume_info, size_t n) 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, FALSE); + ptid = debug_event_ptid (&windows_process.current_event); + th = windows_process.thread_rec (ptid, DONT_INVALIDATE_CONTEXT); if (th) { win32_prepare_to_resume (th); - if (th->context.ContextFlags) + DWORD *context_flags; +#ifdef __x86_64__ + if (windows_process.wow64_process) + context_flags = &th->wow64_context.ContextFlags; + else +#endif + context_flags = &th->context.ContextFlags; + if (*context_flags) { /* Move register values from the inferior into the thread context structure. */ @@ -977,7 +851,7 @@ win32_process_target::resume (thread_resume *resume_info, size_t n) } win32_set_thread_context (th); - th->context.ContextFlags = 0; + *context_flags = 0; } } @@ -987,21 +861,18 @@ win32_process_target::resume (thread_resume *resume_info, size_t n) 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]; -#ifdef _WIN32_WCE - WIN32_FIND_DATA w32_fd; - WCHAR wname[MAX_PATH + 1]; - mbstowcs (wname, name, MAX_PATH); - HANDLE h = FindFirstFile (wname, &w32_fd); -#else WIN32_FIND_DATAA w32_fd; HANDLE h = FindFirstFileA (name, &w32_fd); -#endif /* The symbols in a dll are offset by 0x1000, which is the offset from 0 of the first byte in an image - because @@ -1014,7 +885,6 @@ win32_add_one_solib (const char *name, CORE_ADDR load_addr) { FindClose (h); strcpy (buf, name); -#ifndef _WIN32_WCE { char cwd[MAX_PATH + 1]; char *p; @@ -1028,16 +898,13 @@ win32_add_one_solib (const char *name, CORE_ADDR load_addr) SetCurrentDirectoryA (cwd); } } -#endif } -#ifndef _WIN32_WCE if (strcasecmp (buf, "ntdll.dll") == 0) { GetSystemDirectoryA (buf, sizeof (buf)); strcat (buf, "\\ntdll.dll"); } -#endif #ifdef __CYGWIN__ cygwin_conv_path (CCP_WIN_A_TO_POSIX, buf, buf2, sizeof (buf2)); @@ -1048,182 +915,10 @@ win32_add_one_solib (const char *name, CORE_ADDR load_addr) loaded_dll (buf2, load_addr); } -static char * -get_image_name (HANDLE h, void *address, int unicode) -{ - static char buf[(2 * MAX_PATH) + 1]; - DWORD size = unicode ? sizeof (WCHAR) : sizeof (char); - char *address_ptr; - int len = 0; - char b[2]; - SIZE_T done; - - /* Attempt to read the name of the dll that was detected. - This is documented to work only when actively debugging - a program. It will not work for attached processes. */ - if (address == NULL) - return NULL; - -#ifdef _WIN32_WCE - /* Windows CE reports the address of the image name, - instead of an address of a pointer into the image name. */ - address_ptr = address; -#else - /* See if we could read the address of a string, and that the - address isn't null. */ - if (!ReadProcessMemory (h, address, &address_ptr, - sizeof (address_ptr), &done) - || done != sizeof (address_ptr) - || !address_ptr) - return NULL; -#endif - - /* Find the length of the string */ - while (ReadProcessMemory (h, address_ptr + len++ * size, &b, size, &done) - && (b[0] != 0 || b[size - 1] != 0) && done == size) - continue; - - if (!unicode) - ReadProcessMemory (h, address_ptr, buf, len, &done); - else - { - WCHAR *unicode_address = XALLOCAVEC (WCHAR, len); - ReadProcessMemory (h, address_ptr, unicode_address, len * sizeof (WCHAR), - &done); - - WideCharToMultiByte (CP_ACP, 0, unicode_address, len, buf, len, 0, 0); - } - - return buf; -} - -typedef BOOL (WINAPI *winapi_EnumProcessModules) (HANDLE, HMODULE *, - DWORD, LPDWORD); -typedef BOOL (WINAPI *winapi_GetModuleInformation) (HANDLE, HMODULE, - LPMODULEINFO, DWORD); -typedef DWORD (WINAPI *winapi_GetModuleFileNameExA) (HANDLE, HMODULE, - LPSTR, DWORD); - -static winapi_EnumProcessModules win32_EnumProcessModules; -static winapi_GetModuleInformation win32_GetModuleInformation; -static winapi_GetModuleFileNameExA win32_GetModuleFileNameExA; - -static BOOL -load_psapi (void) -{ - static int psapi_loaded = 0; - static HMODULE dll = NULL; - - if (!psapi_loaded) - { - psapi_loaded = 1; - dll = LoadLibrary (TEXT("psapi.dll")); - if (!dll) - return FALSE; - win32_EnumProcessModules = - GETPROCADDRESS (dll, EnumProcessModules); - win32_GetModuleInformation = - GETPROCADDRESS (dll, GetModuleInformation); - win32_GetModuleFileNameExA = - GETPROCADDRESS (dll, GetModuleFileNameExA); - } - - return (win32_EnumProcessModules != NULL - && win32_GetModuleInformation != NULL - && win32_GetModuleFileNameExA != NULL); -} - -#ifndef _WIN32_WCE - -/* Iterate over all DLLs currently mapped by our inferior, and - add them to our list of solibs. */ - -static void -win32_add_all_dlls (void) -{ - size_t i; - HMODULE dh_buf[1]; - HMODULE *DllHandle = dh_buf; - DWORD cbNeeded; - BOOL ok; - - if (!load_psapi ()) - return; - - cbNeeded = 0; - ok = (*win32_EnumProcessModules) (current_process_handle, - DllHandle, - sizeof (HMODULE), - &cbNeeded); - - if (!ok || !cbNeeded) - return; - - DllHandle = (HMODULE *) alloca (cbNeeded); - if (!DllHandle) - return; - - ok = (*win32_EnumProcessModules) (current_process_handle, - DllHandle, - cbNeeded, - &cbNeeded); - if (!ok) - return; - - for (i = 1; i < ((size_t) cbNeeded / sizeof (HMODULE)); i++) - { - MODULEINFO mi; - char dll_name[MAX_PATH]; - - if (!(*win32_GetModuleInformation) (current_process_handle, - DllHandle[i], - &mi, - sizeof (mi))) - continue; - if ((*win32_GetModuleFileNameExA) (current_process_handle, - DllHandle[i], - dll_name, - MAX_PATH) == 0) - continue; - win32_add_one_solib (dll_name, (CORE_ADDR) (uintptr_t) mi.lpBaseOfDll); - } -} -#endif - -typedef HANDLE (WINAPI *winapi_CreateToolhelp32Snapshot) (DWORD, DWORD); -typedef BOOL (WINAPI *winapi_Module32First) (HANDLE, LPMODULEENTRY32); -typedef BOOL (WINAPI *winapi_Module32Next) (HANDLE, LPMODULEENTRY32); - -/* Handle a DLL load event. - - This function assumes that this event did not occur during inferior - initialization, where their event info may be incomplete (see - do_initial_child_stuff and win32_add_all_dlls for more info on - how we handle DLL loading during that phase). */ - -static void -handle_load_dll (void) -{ - LOAD_DLL_DEBUG_INFO *event = ¤t_event.u.LoadDll; - char *dll_name; - - dll_name = get_image_name (current_process_handle, - event->lpImageName, event->fUnicode); - if (!dll_name) - return; - - win32_add_one_solib (dll_name, (CORE_ADDR) (uintptr_t) event->lpBaseOfDll); -} - -/* Handle a DLL unload event. - - This function assumes that this event did not occur during inferior - initialization, where their event info may be incomplete (see - do_initial_child_stuff and win32_add_one_solib for more info - on how we handle DLL loading during that phase). */ +/* See nat/windows-nat.h. */ -static void -handle_unload_dll (void) +void +gdbserver_windows_process::handle_unload_dll () { CORE_ADDR load_addr = (CORE_ADDR) (uintptr_t) current_event.u.UnloadDll.lpBaseOfDll; @@ -1235,133 +930,12 @@ handle_unload_dll (void) unloaded_dll (NULL, load_addr); } -static void -handle_exception (struct target_waitstatus *ourstatus) -{ - DWORD code = current_event.u.Exception.ExceptionRecord.ExceptionCode; - - memcpy (&siginfo_er, ¤t_event.u.Exception.ExceptionRecord, - sizeof siginfo_er); - - ourstatus->kind = TARGET_WAITKIND_STOPPED; - - switch (code) - { - case EXCEPTION_ACCESS_VIOLATION: - OUTMSG2 (("EXCEPTION_ACCESS_VIOLATION")); - ourstatus->value.sig = GDB_SIGNAL_SEGV; - break; - case STATUS_STACK_OVERFLOW: - OUTMSG2 (("STATUS_STACK_OVERFLOW")); - ourstatus->value.sig = GDB_SIGNAL_SEGV; - break; - case STATUS_FLOAT_DENORMAL_OPERAND: - OUTMSG2 (("STATUS_FLOAT_DENORMAL_OPERAND")); - ourstatus->value.sig = GDB_SIGNAL_FPE; - break; - case EXCEPTION_ARRAY_BOUNDS_EXCEEDED: - OUTMSG2 (("EXCEPTION_ARRAY_BOUNDS_EXCEEDED")); - ourstatus->value.sig = GDB_SIGNAL_FPE; - break; - case STATUS_FLOAT_INEXACT_RESULT: - OUTMSG2 (("STATUS_FLOAT_INEXACT_RESULT")); - ourstatus->value.sig = GDB_SIGNAL_FPE; - break; - case STATUS_FLOAT_INVALID_OPERATION: - OUTMSG2 (("STATUS_FLOAT_INVALID_OPERATION")); - ourstatus->value.sig = GDB_SIGNAL_FPE; - break; - case STATUS_FLOAT_OVERFLOW: - OUTMSG2 (("STATUS_FLOAT_OVERFLOW")); - ourstatus->value.sig = GDB_SIGNAL_FPE; - break; - case STATUS_FLOAT_STACK_CHECK: - OUTMSG2 (("STATUS_FLOAT_STACK_CHECK")); - ourstatus->value.sig = GDB_SIGNAL_FPE; - break; - case STATUS_FLOAT_UNDERFLOW: - OUTMSG2 (("STATUS_FLOAT_UNDERFLOW")); - ourstatus->value.sig = GDB_SIGNAL_FPE; - break; - case STATUS_FLOAT_DIVIDE_BY_ZERO: - OUTMSG2 (("STATUS_FLOAT_DIVIDE_BY_ZERO")); - ourstatus->value.sig = GDB_SIGNAL_FPE; - break; - case STATUS_INTEGER_DIVIDE_BY_ZERO: - OUTMSG2 (("STATUS_INTEGER_DIVIDE_BY_ZERO")); - ourstatus->value.sig = GDB_SIGNAL_FPE; - break; - case STATUS_INTEGER_OVERFLOW: - OUTMSG2 (("STATUS_INTEGER_OVERFLOW")); - ourstatus->value.sig = GDB_SIGNAL_FPE; - break; - case EXCEPTION_BREAKPOINT: - OUTMSG2 (("EXCEPTION_BREAKPOINT")); - ourstatus->value.sig = GDB_SIGNAL_TRAP; -#ifdef _WIN32_WCE - /* Remove the initial breakpoint. */ - check_breakpoints ((CORE_ADDR) (long) current_event - .u.Exception.ExceptionRecord.ExceptionAddress); -#endif - break; - case DBG_CONTROL_C: - OUTMSG2 (("DBG_CONTROL_C")); - ourstatus->value.sig = GDB_SIGNAL_INT; - break; - case DBG_CONTROL_BREAK: - OUTMSG2 (("DBG_CONTROL_BREAK")); - ourstatus->value.sig = GDB_SIGNAL_INT; - break; - case EXCEPTION_SINGLE_STEP: - OUTMSG2 (("EXCEPTION_SINGLE_STEP")); - ourstatus->value.sig = GDB_SIGNAL_TRAP; - break; - case EXCEPTION_ILLEGAL_INSTRUCTION: - OUTMSG2 (("EXCEPTION_ILLEGAL_INSTRUCTION")); - ourstatus->value.sig = GDB_SIGNAL_ILL; - break; - case EXCEPTION_PRIV_INSTRUCTION: - OUTMSG2 (("EXCEPTION_PRIV_INSTRUCTION")); - ourstatus->value.sig = GDB_SIGNAL_ILL; - break; - case EXCEPTION_NONCONTINUABLE_EXCEPTION: - OUTMSG2 (("EXCEPTION_NONCONTINUABLE_EXCEPTION")); - ourstatus->value.sig = GDB_SIGNAL_ILL; - break; - default: - if (current_event.u.Exception.dwFirstChance) - { - ourstatus->kind = TARGET_WAITKIND_SPURIOUS; - return; - } - OUTMSG2 (("gdbserver: unknown target exception 0x%08x at 0x%s", - (unsigned) current_event.u.Exception.ExceptionRecord.ExceptionCode, - phex_nz ((uintptr_t) current_event.u.Exception.ExceptionRecord. - ExceptionAddress, sizeof (uintptr_t)))); - ourstatus->value.sig = GDB_SIGNAL_UNKNOWN; - break; - } - OUTMSG2 (("\n")); - last_sig = ourstatus->value.sig; -} - - static void suspend_one_thread (thread_info *thread) { - win32_thread_info *th = (win32_thread_info *) thread_target_data (thread); + windows_thread_info *th = (windows_thread_info *) thread_target_data (thread); - if (!th->suspended) - { - if (SuspendThread (th->h) == (DWORD) -1) - { - DWORD err = GetLastError (); - OUTMSG (("warning: SuspendThread failed in suspend_one_thread, " - "(error %d): %s\n", (int) err, strwinerror (err))); - } - else - th->suspended = 1; - } + th->suspend (); } static void @@ -1369,239 +943,255 @@ fake_breakpoint_event (void) { 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); } -#ifdef _WIN32_WCE -static int -auto_delete_breakpoint (CORE_ADDR stop_pc) +/* See nat/windows-nat.h. */ + +bool +gdbserver_windows_process::handle_access_violation + (const EXCEPTION_RECORD *rec) { - return 1; + return false; +} + +/* A helper function that will, if needed, set + 'stopped_at_software_breakpoint' on the thread and adjust the + PC. */ + +static void +maybe_adjust_pc () +{ + struct regcache *regcache = get_thread_regcache (current_thread, 1); + child_fetch_inferior_registers (regcache, -1); + + windows_thread_info *th + = windows_process.thread_rec (current_thread_ptid (), + DONT_INVALIDATE_CONTEXT); + th->stopped_at_software_breakpoint = false; + + if (windows_process.current_event.dwDebugEventCode == EXCEPTION_DEBUG_EVENT + && ((windows_process.current_event.u.Exception.ExceptionRecord.ExceptionCode + == EXCEPTION_BREAKPOINT) + || (windows_process.current_event.u.Exception.ExceptionRecord.ExceptionCode + == STATUS_WX86_BREAKPOINT)) + && windows_process.child_initialization_done) + { + th->stopped_at_software_breakpoint = true; + CORE_ADDR pc = regcache_read_pc (regcache); + CORE_ADDR sw_breakpoint_pc = pc - the_low_target.decr_pc_after_break; + regcache_write_pc (regcache, sw_breakpoint_pc); + } } -#endif /* Get the next event from the child. */ static int -get_child_debug_event (struct target_waitstatus *ourstatus) +get_child_debug_event (DWORD *continue_status, + struct target_waitstatus *ourstatus) { ptid_t ptid; - last_sig = GDB_SIGNAL_0; - ourstatus->kind = TARGET_WAITKIND_SPURIOUS; + 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; } -#ifndef _WIN32_WCE - attaching = 0; -#else - if (attaching) - { - /* WinCE doesn't set an initial breakpoint automatically. To - stop the inferior, we flush all currently pending debug - events -- the thread list and the dll list are always - reported immediatelly without delay, then, we suspend all - threads and pretend we saw a trap at the current PC of the - main thread. - - Contrary to desktop Windows, Windows CE *does* report the dll - names on LOAD_DLL_DEBUG_EVENTs resulting from a - DebugActiveProcess call. This limits the way we can detect - if all the dlls have already been reported. If we get a real - debug event before leaving attaching, the worst that will - happen is the user will see a spurious breakpoint. */ - - current_event.dwDebugEventCode = 0; - if (!WaitForDebugEvent (¤t_event, 0)) - { - OUTMSG2(("no attach events left\n")); - fake_breakpoint_event (); - attaching = 0; - } - else - OUTMSG2(("got attach event\n")); - } - else -#endif - { - /* Keep the wait time low enough for comfortable remote - interruption, but high enough so gdbserver doesn't become a - bottleneck. */ - if (!WaitForDebugEvent (¤t_event, 250)) - { - DWORD e = GetLastError(); - - if (e == ERROR_PIPE_NOT_CONNECTED) - { - /* This will happen if the loader fails to succesfully - load the application, e.g., if the main executable - tries to pull in a non-existing export from a - DLL. */ - ourstatus->kind = TARGET_WAITKIND_EXITED; - ourstatus->value.integer = 1; - return 1; - } + windows_process.attaching = 0; + { + gdb::optional stop + = windows_process.fetch_pending_stop (debug_threads); + if (stop.has_value ()) + { + *ourstatus = stop->status; + windows_process.current_event = stop->event; + ptid = debug_event_ptid (&windows_process.current_event); + switch_to_thread (find_thread_ptid (ptid)); + return 1; + } - return 0; - } - } + /* 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 (&windows_process.current_event, 250)) + { + DWORD e = GetLastError(); + + if (e == ERROR_PIPE_NOT_CONNECTED) + { + /* This will happen if the loader fails to succesfully + load the application, e.g., if the main executable + tries to pull in a non-existing export from a + DLL. */ + ourstatus->set_exited (1); + return 1; + } + + return 0; + } + } 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); - - current_process_handle = current_event.u.CreateProcessInfo.hProcess; - main_thread_id = current_event.dwThreadId; + (unsigned) current_event->dwProcessId, + (unsigned) current_event->dwThreadId)); + CloseHandle (current_event->u.CreateProcessInfo.hFile); - /* Add the main thread. */ - child_add_thread (current_event.dwProcessId, - main_thread_id, - current_event.u.CreateProcessInfo.hThread, - current_event.u.CreateProcessInfo.lpThreadLocalBase); - -#ifdef _WIN32_WCE - if (!attaching) + if (windows_process.open_process_used) { - /* Windows CE doesn't set the initial breakpoint - automatically like the desktop versions of Windows do. - We add it explicitly here. It will be removed as soon as - it is hit. */ - set_breakpoint_at ((CORE_ADDR) (long) current_event.u - .CreateProcessInfo.lpStartAddress, - auto_delete_breakpoint); + CloseHandle (windows_process.handle); + windows_process.open_process_used = false; } -#endif + + 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, + 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, -1); - CloseHandle (current_process_handle); - current_process_handle = NULL; + 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)); - handle_exception (ourstatus); + (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; case OUTPUT_DEBUG_STRING_EVENT: /* 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 (); + (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); - current_thread = find_thread_ptid (ptid); + ptid = debug_event_ptid (&windows_process.current_event); + + 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 (), windows_process.desired_stop_thread_id)); + maybe_adjust_pc (); + windows_process.pending_stops.push_back + ({(DWORD) ptid.lwp (), *ourstatus, *current_event}); + ourstatus->set_spurious (); + } + else + switch_to_thread (find_thread_ptid (ptid)); + return 1; } @@ -1610,48 +1200,49 @@ get_child_debug_event (struct target_waitstatus *ourstatus) Returns the signal which caused the process to stop. */ ptid_t win32_process_target::wait (ptid_t ptid, target_waitstatus *ourstatus, - int options) + target_wait_flags options) { - struct regcache *regcache; - - 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 (ourstatus)) + DWORD continue_status; + 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)); - - regcache = get_thread_regcache (current_thread, 1); - child_fetch_inferior_registers (regcache, -1); - return debug_event_ptid (¤t_event); + { + OUTMSG2 (("Child Stopped with signal = %d \n", + ourstatus->sig ())); + maybe_adjust_pc (); + 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 (DBG_CONTINUE, -1); + child_continue (continue_status, + windows_process.desired_stop_thread_id); break; } } @@ -1698,19 +1289,7 @@ win32_process_target::write_memory (CORE_ADDR memaddr, void win32_process_target::request_interrupt () { - winapi_DebugBreakProcess DebugBreakProcess; - winapi_GenerateConsoleCtrlEvent GenerateConsoleCtrlEvent; - -#ifdef _WIN32_WCE - HMODULE dll = GetModuleHandle (_T("COREDLL.DLL")); -#else - HMODULE dll = GetModuleHandle (_T("KERNEL32.DLL")); -#endif - - GenerateConsoleCtrlEvent = GETPROCADDRESS (dll, GenerateConsoleCtrlEvent); - - if (GenerateConsoleCtrlEvent != NULL - && GenerateConsoleCtrlEvent (CTRL_BREAK_EVENT, current_process_id)) + if (GenerateConsoleCtrlEvent (CTRL_BREAK_EVENT, signal_pid)) return; /* GenerateConsoleCtrlEvent can fail if process id being debugged is @@ -1718,14 +1297,11 @@ win32_process_target::request_interrupt () 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 @@ -1734,65 +1310,6 @@ win32_process_target::supports_hardware_single_step () return true; } -#ifdef _WIN32_WCE -int -win32_error_to_fileio_error (DWORD err) -{ - switch (err) - { - case ERROR_BAD_PATHNAME: - case ERROR_FILE_NOT_FOUND: - case ERROR_INVALID_NAME: - case ERROR_PATH_NOT_FOUND: - return FILEIO_ENOENT; - case ERROR_CRC: - case ERROR_IO_DEVICE: - case ERROR_OPEN_FAILED: - return FILEIO_EIO; - case ERROR_INVALID_HANDLE: - return FILEIO_EBADF; - case ERROR_ACCESS_DENIED: - case ERROR_SHARING_VIOLATION: - return FILEIO_EACCES; - case ERROR_NOACCESS: - return FILEIO_EFAULT; - case ERROR_BUSY: - return FILEIO_EBUSY; - case ERROR_ALREADY_EXISTS: - case ERROR_FILE_EXISTS: - return FILEIO_EEXIST; - case ERROR_BAD_DEVICE: - return FILEIO_ENODEV; - case ERROR_DIRECTORY: - return FILEIO_ENOTDIR; - case ERROR_FILENAME_EXCED_RANGE: - case ERROR_INVALID_DATA: - case ERROR_INVALID_PARAMETER: - case ERROR_NEGATIVE_SEEK: - return FILEIO_EINVAL; - case ERROR_TOO_MANY_OPEN_FILES: - return FILEIO_EMFILE; - case ERROR_HANDLE_DISK_FULL: - case ERROR_DISK_FULL: - return FILEIO_ENOSPC; - case ERROR_WRITE_PROTECT: - return FILEIO_EROFS; - case ERROR_NOT_SUPPORTED: - return FILEIO_ENOSYS; - } - - return FILEIO_EUNKNOWN; -} - -void -win32_process_target::hostio_last_error (char *buf) -{ - DWORD winerr = GetLastError (); - int fileio_err = win32_error_to_fileio_error (winerr); - sprintf (buf, "F-1,%x", fileio_err); -} -#endif - bool win32_process_target::supports_qxfer_siginfo () { @@ -1807,19 +1324,43 @@ win32_process_target::qxfer_siginfo (const char *annex, 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; - if (offset > 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 (windows_process.wow64_process) + { + buf = (char *) &er32; + bufsize = sizeof (er32); + + 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] + = windows_process.siginfo_er.ExceptionInformation[i]; + } +#endif + + if (offset > bufsize) return -1; - if (offset + len > sizeof (siginfo_er)) - len = sizeof (siginfo_er) - offset; + if (offset + len > bufsize) + len = bufsize - offset; - memcpy (readbuf, (char *) &siginfo_er + offset, len); + memcpy (readbuf, buf + offset, len); return len; } @@ -1835,8 +1376,8 @@ win32_process_target::supports_get_tib_address () int win32_process_target::get_tib_address (ptid_t ptid, CORE_ADDR *addr) { - win32_thread_info *th; - th = thread_rec (ptid, 0); + windows_thread_info *th; + th = windows_process.thread_rec (ptid, DONT_INVALIDATE_CONTEXT); if (th == NULL) return 0; if (addr != NULL) @@ -1846,46 +1387,65 @@ win32_process_target::get_tib_address (ptid_t ptid, CORE_ADDR *addr) /* Implementation of the target_ops method "sw_breakpoint_from_kind". */ -static const gdb_byte * -win32_sw_breakpoint_from_kind (int kind, int *size) +const gdb_byte * +win32_process_target::sw_breakpoint_from_kind (int kind, int *size) { *size = the_low_target.breakpoint_len; return the_low_target.breakpoint; } +bool +win32_process_target::stopped_by_sw_breakpoint () +{ + windows_thread_info *th + = windows_process.thread_rec (current_thread_ptid (), + DONT_INVALIDATE_CONTEXT); + return th == nullptr ? false : th->stopped_at_software_breakpoint; +} + +bool +win32_process_target::supports_stopped_by_sw_breakpoint () +{ + return true; +} + +CORE_ADDR +win32_process_target::read_pc (struct regcache *regcache) +{ + return (*the_low_target.get_pc) (regcache); +} + +void +win32_process_target::write_pc (struct regcache *regcache, CORE_ADDR pc) +{ + return (*the_low_target.set_pc) (regcache, pc); +} + +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; -static process_stratum_target win32_target_ops = { - NULL, /* emit_ops */ - NULL, /* supports_disable_randomization */ - NULL, /* qxfer_libraries_svr4 */ - NULL, /* support_agent */ - NULL, /* enable_btrace */ - NULL, /* disable_btrace */ - NULL, /* read_btrace */ - NULL, /* read_btrace_conf */ - NULL, /* supports_range_stepping */ - NULL, /* pid_to_exec_file */ - NULL, /* multifs_open */ - NULL, /* multifs_unlink */ - NULL, /* multifs_readlink */ - NULL, /* breakpoint_kind_from_pc */ - win32_sw_breakpoint_from_kind, - NULL, /* thread_name */ - NULL, /* breakpoint_kind_from_current_state */ - NULL, /* supports_software_single_step */ - NULL, /* supports_catch_syscall */ - NULL, /* get_ipa_tdesc_idx */ - NULL, /* thread_handle */ - &the_win32_target, -}; - /* Initialize the Win32 backend. */ void initialize_low (void) { - set_target_ops (&win32_target_ops); + set_target_ops (&the_win32_target); the_low_target.arch_setup (); + + initialize_loadable (); }