| /* Low level interface to Windows debugging, for gdbserver. | 
 |    Copyright (C) 2006-2023 Free Software Foundation, Inc. | 
 |  | 
 |    Contributed by Leo Zayas.  Based on "win32-nat.c" from GDB. | 
 |  | 
 |    This file is part of GDB. | 
 |  | 
 |    This program is free software; you can redistribute it and/or modify | 
 |    it under the terms of the GNU General Public License as published by | 
 |    the Free Software Foundation; either version 3 of the License, or | 
 |    (at your option) any later version. | 
 |  | 
 |    This program is distributed in the hope that it will be useful, | 
 |    but WITHOUT ANY WARRANTY; without even the implied warranty of | 
 |    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
 |    GNU General Public License for more details. | 
 |  | 
 |    You should have received a copy of the GNU General Public License | 
 |    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */ | 
 |  | 
 | #include "server.h" | 
 | #include "regcache.h" | 
 | #include "gdbsupport/fileio.h" | 
 | #include "mem-break.h" | 
 | #include "win32-low.h" | 
 | #include "gdbthread.h" | 
 | #include "dll.h" | 
 | #include "hostio.h" | 
 | #include <windows.h> | 
 | #include <winnt.h> | 
 | #include <imagehlp.h> | 
 | #include <tlhelp32.h> | 
 | #include <psapi.h> | 
 | #include <process.h> | 
 | #include "gdbsupport/gdb_tilde_expand.h" | 
 | #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 <sys/cygwin.h> | 
 | #endif | 
 |  | 
 | #define OUTMSG(X) do { printf X; fflush (stderr); } while (0) | 
 |  | 
 | #define OUTMSG2(X) \ | 
 |   do						\ | 
 |     {						\ | 
 |       if (debug_threads)			\ | 
 | 	{					\ | 
 | 	  printf X;				\ | 
 | 	  fflush (stderr);			\ | 
 | 	}					\ | 
 |     } while (0) | 
 |  | 
 | #ifndef _T | 
 | #define _T(x) TEXT (x) | 
 | #endif | 
 |  | 
 | int using_threads = 1; | 
 |  | 
 | const struct target_desc *win32_tdesc; | 
 | #ifdef __x86_64__ | 
 | const struct target_desc *wow64_win32_tdesc; | 
 | #endif | 
 |  | 
 | #define NUM_REGS (the_low_target.num_regs ()) | 
 |  | 
 | /* Get the thread ID from the current selected inferior (the current | 
 |    thread).  */ | 
 | static ptid_t | 
 | current_thread_ptid (void) | 
 | { | 
 |   return current_ptid; | 
 | } | 
 |  | 
 | /* The current debug event from WaitForDebugEvent.  */ | 
 | static ptid_t | 
 | debug_event_ptid (DEBUG_EVENT *event) | 
 | { | 
 |   return ptid_t (event->dwProcessId, event->dwThreadId, 0); | 
 | } | 
 |  | 
 | /* Get the thread context of the thread associated with TH.  */ | 
 |  | 
 | static void | 
 | win32_get_thread_context (windows_thread_info *th) | 
 | { | 
 | #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 (windows_thread_info *th) | 
 | { | 
 | #ifdef __x86_64__ | 
 |   if (windows_process.wow64_process) | 
 |     Wow64SetThreadContext (th->h, &th->wow64_context); | 
 |   else | 
 | #endif | 
 |     SetThreadContext (th->h, &th->context); | 
 | } | 
 |  | 
 | /* Set the thread context of the thread associated with TH.  */ | 
 |  | 
 | static void | 
 | win32_prepare_to_resume (windows_thread_info *th) | 
 | { | 
 |   if (the_low_target.prepare_to_resume != NULL) | 
 |     (*the_low_target.prepare_to_resume) (th); | 
 | } | 
 |  | 
 | /* See win32-low.h.  */ | 
 |  | 
 | void | 
 | win32_require_context (windows_thread_info *th) | 
 | { | 
 |   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) | 
 |     { | 
 |       th->suspend (); | 
 |       win32_get_thread_context (th); | 
 |     } | 
 | } | 
 |  | 
 | /* 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; | 
 |  | 
 |   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 windows_thread_info * | 
 | child_add_thread (DWORD pid, DWORD tid, HANDLE h, void *tlb) | 
 | { | 
 |   windows_thread_info *th; | 
 |   ptid_t ptid = ptid_t (pid, tid, 0); | 
 |  | 
 |   if ((th = windows_process.thread_rec (ptid, DONT_INVALIDATE_CONTEXT))) | 
 |     return th; | 
 |  | 
 |   CORE_ADDR base = (CORE_ADDR) (uintptr_t) tlb; | 
 | #ifdef __x86_64__ | 
 |   /* For WOW64 processes, this is actually the pointer to the 64bit TIB, | 
 |      and the 32bit TIB is exactly 2 pages after it.  */ | 
 |   if (windows_process.wow64_process) | 
 |     base += 2 * 4096; /* page size = 4096 */ | 
 | #endif | 
 |   th = new windows_thread_info (tid, h, base); | 
 |  | 
 |   add_thread (ptid, th); | 
 |  | 
 |   if (the_low_target.thread_added != NULL) | 
 |     (*the_low_target.thread_added) (th); | 
 |  | 
 |   return th; | 
 | } | 
 |  | 
 | /* Delete a thread from the list of threads.  */ | 
 | static void | 
 | delete_thread_info (thread_info *thread) | 
 | { | 
 |   windows_thread_info *th = (windows_thread_info *) thread_target_data (thread); | 
 |  | 
 |   remove_thread (thread); | 
 |   delete th; | 
 | } | 
 |  | 
 | /* Delete a thread from the list of threads.  */ | 
 | static void | 
 | child_delete_thread (DWORD pid, DWORD tid) | 
 | { | 
 |   /* If the last thread is exiting, just return.  */ | 
 |   if (all_threads.size () == 1) | 
 |     return; | 
 |  | 
 |   thread_info *thread = find_thread_ptid (ptid_t (pid, tid)); | 
 |   if (thread == NULL) | 
 |     return; | 
 |  | 
 |   delete_thread_info (thread); | 
 | } | 
 |  | 
 | /* These watchpoint related wrapper functions simply pass on the function call | 
 |    if the low target has registered a corresponding function.  */ | 
 |  | 
 | bool | 
 | win32_process_target::supports_z_point_type (char 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 (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).  */ | 
 |     return 1; | 
 | } | 
 |  | 
 | int | 
 | win32_process_target::remove_point (enum raw_bkpt_type type, CORE_ADDR addr, | 
 | 				    int size, raw_breakpoint *bp) | 
 | { | 
 |   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).  */ | 
 |     return 1; | 
 | } | 
 |  | 
 | bool | 
 | win32_process_target::stopped_by_watchpoint () | 
 | { | 
 |   if (the_low_target.stopped_by_watchpoint != NULL) | 
 |     return the_low_target.stopped_by_watchpoint (); | 
 |   else | 
 |     return false; | 
 | } | 
 |  | 
 | CORE_ADDR | 
 | win32_process_target::stopped_data_address () | 
 | { | 
 |   if (the_low_target.stopped_data_address != NULL) | 
 |     return the_low_target.stopped_data_address (); | 
 |   else | 
 |     return 0; | 
 | } | 
 |  | 
 |  | 
 | /* Transfer memory from/to the debugged process.  */ | 
 | static int | 
 | child_xfer_memory (CORE_ADDR memaddr, char *our, int len, | 
 | 		   int write, process_stratum_target *target) | 
 | { | 
 |   BOOL success; | 
 |   SIZE_T done = 0; | 
 |   DWORD lasterror = 0; | 
 |   uintptr_t addr = (uintptr_t) memaddr; | 
 |  | 
 |   if (write) | 
 |     { | 
 |       success = WriteProcessMemory (windows_process.handle, (LPVOID) addr, | 
 | 				    (LPCVOID) our, len, &done); | 
 |       if (!success) | 
 | 	lasterror = GetLastError (); | 
 |       FlushInstructionCache (windows_process.handle, (LPCVOID) addr, len); | 
 |     } | 
 |   else | 
 |     { | 
 |       success = ReadProcessMemory (windows_process.handle, (LPCVOID) addr, | 
 | 				   (LPVOID) our, len, &done); | 
 |       if (!success) | 
 | 	lasterror = GetLastError (); | 
 |     } | 
 |   if (!success && lasterror == ERROR_PARTIAL_COPY && done > 0) | 
 |     return done; | 
 |   else | 
 |     return success ? done : -1; | 
 | } | 
 |  | 
 | /* Clear out any old thread list and reinitialize it to a pristine | 
 |    state. */ | 
 | static void | 
 | child_init_thread_list (void) | 
 | { | 
 |   for_each_thread (delete_thread_info); | 
 | } | 
 |  | 
 | static void | 
 | do_initial_child_stuff (HANDLE proch, DWORD pid, int attached) | 
 | { | 
 |   struct process_info *proc; | 
 |  | 
 |   windows_process.last_sig = GDB_SIGNAL_0; | 
 |   windows_process.handle = proch; | 
 |   windows_process.main_thread_id = 0; | 
 |  | 
 |   windows_process.soft_interrupt_requested = 0; | 
 |   windows_process.faked_breakpoint = 0; | 
 |   windows_process.open_process_used = true; | 
 |  | 
 |   memset (&windows_process.current_event, 0, | 
 | 	  sizeof (windows_process.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); | 
 | #ifdef __x86_64__ | 
 |   if (windows_process.wow64_process) | 
 |     proc->tdesc = wow64_win32_tdesc; | 
 |   else | 
 | #endif | 
 |     proc->tdesc = win32_tdesc; | 
 |   child_init_thread_list (); | 
 |   windows_process.child_initialization_done = 0; | 
 |  | 
 |   if (the_low_target.initial_stuff != NULL) | 
 |     (*the_low_target.initial_stuff) (); | 
 |  | 
 |   windows_process.cached_status.set_ignore (); | 
 |  | 
 |   /* Flush all currently pending debug events (thread and dll list) up | 
 |      to the initial breakpoint.  */ | 
 |   while (1) | 
 |     { | 
 |       struct target_waitstatus status; | 
 |  | 
 |       the_target->wait (minus_one_ptid, &status, 0); | 
 |  | 
 |       /* Note win32_wait doesn't return thread events.  */ | 
 |       if (status.kind () != TARGET_WAITKIND_LOADED) | 
 | 	{ | 
 | 	  windows_process.cached_status = status; | 
 | 	  break; | 
 | 	} | 
 |  | 
 |       { | 
 | 	struct thread_resume resume; | 
 |  | 
 | 	resume.thread = minus_one_ptid; | 
 | 	resume.kind = resume_continue; | 
 | 	resume.sig = 0; | 
 |  | 
 | 	the_target->resume (&resume, 1); | 
 |       } | 
 |     } | 
 |  | 
 |   /* Now that the inferior has been started and all DLLs have been mapped, | 
 |      we can iterate over all DLLs and load them in. | 
 |  | 
 |      We avoid doing it any earlier because, on certain versions of Windows, | 
 |      LOAD_DLL_DEBUG_EVENTs are sometimes not complete.  In particular, | 
 |      we have seen on Windows 8.1 that the ntdll.dll load event does not | 
 |      include the DLL name, preventing us from creating an associated SO. | 
 |      A possible explanation is that ntdll.dll might be mapped before | 
 |      the SO info gets created by the Windows system -- ntdll.dll is | 
 |      the first DLL to be reported via LOAD_DLL_DEBUG_EVENT and other DLLs | 
 |      do not seem to suffer from that problem. | 
 |  | 
 |      Rather than try to work around this sort of issue, it is much | 
 |      simpler to just ignore DLL load/unload events during the startup | 
 |      phase, and then process them all in one batch now.  */ | 
 |   windows_process.add_all_dlls (); | 
 |  | 
 |   windows_process.child_initialization_done = 1; | 
 | } | 
 |  | 
 | /* Resume all artificially suspended threads if we are continuing | 
 |    execution.  */ | 
 | static void | 
 | continue_one_thread (thread_info *thread, int thread_id) | 
 | { | 
 |   windows_thread_info *th = (windows_thread_info *) thread_target_data (thread); | 
 |  | 
 |   if (thread_id == -1 || thread_id == th->tid) | 
 |     { | 
 |       win32_prepare_to_resume (th); | 
 |  | 
 |       if (th->suspended) | 
 | 	{ | 
 | 	  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); | 
 | 	      *context_flags = 0; | 
 | 	    } | 
 |  | 
 | 	  th->resume (); | 
 | 	} | 
 |     } | 
 | } | 
 |  | 
 | 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); | 
 |     }); | 
 |   windows_process.faked_breakpoint = 0; | 
 |  | 
 |   return continue_last_debug_event (continue_status, debug_threads); | 
 | } | 
 |  | 
 | /* Fetch register(s) from the current thread context.  */ | 
 | static void | 
 | child_fetch_inferior_registers (struct regcache *regcache, int r) | 
 | { | 
 |   int regno; | 
 |   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 | 
 |     for (regno = 0; regno < r; regno++) | 
 |       (*the_low_target.fetch_inferior_register) (regcache, th, regno); | 
 | } | 
 |  | 
 | /* Store a new register value into the current thread context.  We don't | 
 |    change the program's context until later, when we resume it.  */ | 
 | static void | 
 | child_store_inferior_registers (struct regcache *regcache, int r) | 
 | { | 
 |   int regno; | 
 |   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 | 
 |     for (regno = 0; regno < r; regno++) | 
 |       (*the_low_target.store_inferior_register) (regcache, th, regno); | 
 | } | 
 |  | 
 | static BOOL | 
 | create_process (const char *program, char *args, | 
 | 		DWORD flags, PROCESS_INFORMATION *pi) | 
 | { | 
 |   const std::string &inferior_cwd = get_inferior_cwd (); | 
 |   BOOL ret; | 
 |   size_t argslen, proglen; | 
 |  | 
 |   proglen = strlen (program) + 1; | 
 |   argslen = strlen (args) + proglen; | 
 |  | 
 |   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 = create_process (program,           /* image name */ | 
 | 			program_and_args,  /* command line */ | 
 | 			flags,             /* start flags */ | 
 | 			NULL,              /* environment */ | 
 | 			/* current directory */ | 
 | 			(inferior_cwd.empty () | 
 | 			 ? NULL | 
 | 			 : gdb_tilde_expand (inferior_cwd.c_str ()).c_str()), | 
 | 			get_client_state ().disable_randomization, | 
 | 			&si,               /* start info */ | 
 | 			pi);               /* proc info */ | 
 |  | 
 |   return ret; | 
 | } | 
 |  | 
 | /* Start a new process. | 
 |    PROGRAM is the program name. | 
 |    PROGRAM_ARGS is the vector containing the inferior's args. | 
 |    Returns the new PID on success, -1 on failure.  Registers the new | 
 |    process with the process list.  */ | 
 | int | 
 | win32_process_target::create_inferior (const char *program, | 
 | 				       const std::vector<char *> &program_args) | 
 | { | 
 |   client_state &cs = get_client_state (); | 
 | #ifndef USE_WIN32API | 
 |   char real_path[PATH_MAX]; | 
 |   char *orig_path, *new_path, *path_ptr; | 
 | #endif | 
 |   BOOL ret; | 
 |   DWORD flags; | 
 |   PROCESS_INFORMATION pi; | 
 |   DWORD err; | 
 |   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.  */ | 
 |   windows_process.attaching = 0; | 
 |  | 
 |   if (!program) | 
 |     error ("No executable specified, specify executable to debug.\n"); | 
 |  | 
 |   flags = DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS; | 
 |  | 
 | #ifndef USE_WIN32API | 
 |   orig_path = NULL; | 
 |   path_ptr = getenv ("PATH"); | 
 |   if (path_ptr) | 
 |     { | 
 |       int size = cygwin_conv_path_list (CCP_POSIX_TO_WIN_A, path_ptr, NULL, 0); | 
 |       orig_path = (char *) alloca (strlen (path_ptr) + 1); | 
 |       new_path = (char *) alloca (size); | 
 |       strcpy (orig_path, path_ptr); | 
 |       cygwin_conv_path_list (CCP_POSIX_TO_WIN_A, path_ptr, new_path, size); | 
 |       setenv ("PATH", new_path, 1); | 
 |      } | 
 |   cygwin_conv_path (CCP_POSIX_TO_WIN_A, program, real_path, PATH_MAX); | 
 |   program = real_path; | 
 | #endif | 
 |  | 
 |   OUTMSG2 (("Command line is \"%s %s\"\n", program, args)); | 
 |  | 
 | #ifdef CREATE_NEW_PROCESS_GROUP | 
 |   flags |= CREATE_NEW_PROCESS_GROUP; | 
 | #endif | 
 |  | 
 |   ret = create_process (program, args, flags, &pi); | 
 |   err = GetLastError (); | 
 |   if (!ret && err == ERROR_FILE_NOT_FOUND) | 
 |     { | 
 |       char *exename = (char *) alloca (strlen (program) + 5); | 
 |       strcat (strcpy (exename, program), ".exe"); | 
 |       ret = create_process (exename, args, flags, &pi); | 
 |       err = GetLastError (); | 
 |     } | 
 |  | 
 | #ifndef USE_WIN32API | 
 |   if (orig_path) | 
 |     setenv ("PATH", orig_path, 1); | 
 | #endif | 
 |  | 
 |   if (!ret) | 
 |     { | 
 |       error ("Error creating process \"%s %s\", (error %d): %s\n", | 
 | 	     program, args, (int) err, strwinerror (err)); | 
 |     } | 
 |   else | 
 |     { | 
 |       OUTMSG2 (("Process created: %s %s\n", program, (char *) args)); | 
 |     } | 
 |  | 
 |   CloseHandle (pi.hThread); | 
 |  | 
 |   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 (pi.dwProcessId), &cs.last_status, 0); | 
 |  | 
 |   /* Necessary for handle_v_kill.  */ | 
 |   signal_pid = pi.dwProcessId; | 
 |  | 
 |   return pi.dwProcessId; | 
 | } | 
 |  | 
 | /* Attach to a running process. | 
 |    PID is the process ID to attach to, specified by the user | 
 |    or a higher layer.  */ | 
 | int | 
 | win32_process_target::attach (unsigned long pid) | 
 | { | 
 |   HANDLE h; | 
 |   DWORD err; | 
 |  | 
 |   h = OpenProcess (PROCESS_ALL_ACCESS, FALSE, pid); | 
 |   if (h != NULL) | 
 |     { | 
 |       if (DebugActiveProcess (pid)) | 
 | 	{ | 
 | 	  DebugSetProcessKillOnExit (FALSE); | 
 |  | 
 | 	  /* win32_wait needs to know we're attaching.  */ | 
 | 	  windows_process.attaching = 1; | 
 | 	  do_initial_child_stuff (h, pid, 1); | 
 | 	  return 0; | 
 | 	} | 
 |  | 
 |       CloseHandle (h); | 
 |     } | 
 |  | 
 |   err = GetLastError (); | 
 |   error ("Attach to process failed (error %d): %s\n", | 
 | 	 (int) err, strwinerror (err)); | 
 | } | 
 |  | 
 | /* 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; | 
 |   char s[READ_BUFFER_LEN + 1] = { 0 }; | 
 |   DWORD nbytes = current_event.u.DebugString.nDebugStringLength; | 
 |  | 
 |   if (nbytes == 0) | 
 |     return 0; | 
 |  | 
 |   if (nbytes > READ_BUFFER_LEN) | 
 |     nbytes = READ_BUFFER_LEN; | 
 |  | 
 |   addr = (CORE_ADDR) (size_t) current_event.u.DebugString.lpDebugStringData; | 
 |  | 
 |   if (current_event.u.DebugString.fUnicode) | 
 |     { | 
 |       /* The event tells us how many bytes, not chars, even | 
 | 	 in Unicode.  */ | 
 |       WCHAR buffer[(READ_BUFFER_LEN + 1) / sizeof (WCHAR)] = { 0 }; | 
 |       if (read_inferior_memory (addr, (unsigned char *) buffer, nbytes) != 0) | 
 | 	return 0; | 
 |       wcstombs (s, buffer, (nbytes + 1) / sizeof (WCHAR)); | 
 |     } | 
 |   else | 
 |     { | 
 |       if (read_inferior_memory (addr, (unsigned char *) s, nbytes) != 0) | 
 | 	return 0; | 
 |     } | 
 |  | 
 |   if (!startswith (s, "cYg")) | 
 |     { | 
 |       if (!server_waiting) | 
 | 	{ | 
 | 	  OUTMSG2(("%s", s)); | 
 | 	  return 0; | 
 | 	} | 
 |  | 
 |       monitor_output (s); | 
 |     } | 
 | #undef READ_BUFFER_LEN | 
 |  | 
 |   return 0; | 
 | } | 
 |  | 
 | static void | 
 | win32_clear_inferiors (void) | 
 | { | 
 |   if (windows_process.open_process_used) | 
 |     { | 
 |       CloseHandle (windows_process.handle); | 
 |       windows_process.open_process_used = false; | 
 |     } | 
 |  | 
 |   for_each_thread (delete_thread_info); | 
 |   windows_process.siginfo_er.ExceptionCode = 0; | 
 |   clear_inferiors (); | 
 | } | 
 |  | 
 | /* Implementation of target_ops::kill.  */ | 
 |  | 
 | int | 
 | win32_process_target::kill (process_info *process) | 
 | { | 
 |   TerminateProcess (windows_process.handle, 0); | 
 |   for (;;) | 
 |     { | 
 |       if (!child_continue (DBG_CONTINUE, -1)) | 
 | 	break; | 
 |       if (!wait_for_debug_event (&windows_process.current_event, INFINITE)) | 
 | 	break; | 
 |       if (windows_process.current_event.dwDebugEventCode | 
 | 	  == EXIT_PROCESS_DEBUG_EVENT) | 
 | 	break; | 
 |       else if (windows_process.current_event.dwDebugEventCode | 
 | 	       == OUTPUT_DEBUG_STRING_EVENT) | 
 | 	windows_process.handle_output_debug_string (nullptr); | 
 |     } | 
 |  | 
 |   win32_clear_inferiors (); | 
 |  | 
 |   remove_process (process); | 
 |   return 0; | 
 | } | 
 |  | 
 | /* Implementation of target_ops::detach.  */ | 
 |  | 
 | int | 
 | win32_process_target::detach (process_info *process) | 
 | { | 
 |   struct thread_resume resume; | 
 |   resume.thread = minus_one_ptid; | 
 |   resume.kind = resume_continue; | 
 |   resume.sig = 0; | 
 |   this->resume (&resume, 1); | 
 |  | 
 |   if (!DebugActiveProcessStop (process->pid)) | 
 |     return -1; | 
 |  | 
 |   DebugSetProcessKillOnExit (FALSE); | 
 |   remove_process (process); | 
 |  | 
 |   win32_clear_inferiors (); | 
 |   return 0; | 
 | } | 
 |  | 
 | void | 
 | win32_process_target::mourn (struct process_info *process) | 
 | { | 
 |   remove_process (process); | 
 | } | 
 |  | 
 | /* Implementation of target_ops::join.  */ | 
 |  | 
 | void | 
 | win32_process_target::join (int pid) | 
 | { | 
 |   HANDLE h = OpenProcess (PROCESS_ALL_ACCESS, FALSE, pid); | 
 |   if (h != NULL) | 
 |     { | 
 |       WaitForSingleObject (h, INFINITE); | 
 |       CloseHandle (h); | 
 |     } | 
 | } | 
 |  | 
 | /* Return true iff the thread with thread ID TID is alive.  */ | 
 | bool | 
 | win32_process_target::thread_alive (ptid_t ptid) | 
 | { | 
 |   /* Our thread list is reliable; don't bother to poll target | 
 |      threads.  */ | 
 |   return find_thread_ptid (ptid) != NULL; | 
 | } | 
 |  | 
 | /* Resume the inferior process.  RESUME_INFO describes how we want | 
 |    to resume.  */ | 
 | void | 
 | win32_process_target::resume (thread_resume *resume_info, size_t n) | 
 | { | 
 |   DWORD tid; | 
 |   enum gdb_signal sig; | 
 |   int step; | 
 |   windows_thread_info *th; | 
 |   DWORD continue_status = DBG_CONTINUE; | 
 |   ptid_t ptid; | 
 |  | 
 |   /* This handles the very limited set of resume packets that GDB can | 
 |      currently produce.  */ | 
 |  | 
 |   if (n == 1 && resume_info[0].thread == minus_one_ptid) | 
 |     tid = -1; | 
 |   else if (n > 1) | 
 |     tid = -1; | 
 |   else | 
 |     /* Yes, we're ignoring resume_info[0].thread.  It'd be tricky to make | 
 |        the Windows resume code do the right thing for thread switching.  */ | 
 |     tid = windows_process.current_event.dwThreadId; | 
 |  | 
 |   if (resume_info[0].thread != minus_one_ptid) | 
 |     { | 
 |       sig = gdb_signal_from_host (resume_info[0].sig); | 
 |       step = resume_info[0].kind == resume_step; | 
 |     } | 
 |   else | 
 |     { | 
 |       sig = GDB_SIGNAL_0; | 
 |       step = 0; | 
 |     } | 
 |  | 
 |   if (sig != GDB_SIGNAL_0) | 
 |     { | 
 |       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 == windows_process.last_sig) | 
 | 	continue_status = DBG_EXCEPTION_NOT_HANDLED; | 
 |       else | 
 | 	OUTMSG (("Can only continue with received signal %s.\n", | 
 | 		 gdb_signal_to_string (windows_process.last_sig))); | 
 |     } | 
 |  | 
 |   windows_process.last_sig = GDB_SIGNAL_0; | 
 |  | 
 |   /* Get context for the currently selected thread.  */ | 
 |   ptid = debug_event_ptid (&windows_process.current_event); | 
 |   th = windows_process.thread_rec (ptid, DONT_INVALIDATE_CONTEXT); | 
 |   if (th) | 
 |     { | 
 |       win32_prepare_to_resume (th); | 
 |  | 
 |       DWORD *context_flags; | 
 | #ifdef __x86_64__ | 
 |       if (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.  */ | 
 | 	  regcache_invalidate (); | 
 |  | 
 | 	  if (step) | 
 | 	    { | 
 | 	      if (the_low_target.single_step != NULL) | 
 | 		(*the_low_target.single_step) (th); | 
 | 	      else | 
 | 		error ("Single stepping is not supported " | 
 | 		       "in this configuration.\n"); | 
 | 	    } | 
 |  | 
 | 	  win32_set_thread_context (th); | 
 | 	  *context_flags = 0; | 
 | 	} | 
 |     } | 
 |  | 
 |   /* Allow continuing with the same signal that interrupted us. | 
 |      Otherwise complain.  */ | 
 |  | 
 |   child_continue (continue_status, tid); | 
 | } | 
 |  | 
 | /* 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]; | 
 |  | 
 |   WIN32_FIND_DATAA w32_fd; | 
 |   HANDLE h = FindFirstFileA (name, &w32_fd); | 
 |  | 
 |   /* The symbols in a dll are offset by 0x1000, which is the | 
 |      offset from 0 of the first byte in an image - because | 
 |      of the file header and the section alignment. */ | 
 |   load_addr += 0x1000; | 
 |  | 
 |   if (h == INVALID_HANDLE_VALUE) | 
 |     strcpy (buf, name); | 
 |   else | 
 |     { | 
 |       FindClose (h); | 
 |       strcpy (buf, name); | 
 |       { | 
 | 	char cwd[MAX_PATH + 1]; | 
 | 	char *p; | 
 | 	if (GetCurrentDirectoryA (MAX_PATH + 1, cwd)) | 
 | 	  { | 
 | 	    p = strrchr (buf, '\\'); | 
 | 	    if (p) | 
 | 	      p[1] = '\0'; | 
 | 	    SetCurrentDirectoryA (buf); | 
 | 	    GetFullPathNameA (w32_fd.cFileName, MAX_PATH, buf, &p); | 
 | 	    SetCurrentDirectoryA (cwd); | 
 | 	  } | 
 |       } | 
 |     } | 
 |  | 
 |   if (strcasecmp (buf, "ntdll.dll") == 0) | 
 |     { | 
 |       GetSystemDirectoryA (buf, sizeof (buf)); | 
 |       strcat (buf, "\\ntdll.dll"); | 
 |     } | 
 |  | 
 | #ifdef __CYGWIN__ | 
 |   cygwin_conv_path (CCP_WIN_A_TO_POSIX, buf, buf2, sizeof (buf2)); | 
 | #else | 
 |   strcpy (buf2, buf); | 
 | #endif | 
 |  | 
 |   loaded_dll (buf2, load_addr); | 
 | } | 
 |  | 
 | /* See nat/windows-nat.h.  */ | 
 |  | 
 | void | 
 | gdbserver_windows_process::handle_unload_dll () | 
 | { | 
 |   CORE_ADDR load_addr = | 
 | 	  (CORE_ADDR) (uintptr_t) current_event.u.UnloadDll.lpBaseOfDll; | 
 |  | 
 |   /* The symbols in a dll are offset by 0x1000, which is the | 
 |      offset from 0 of the first byte in an image - because | 
 |      of the file header and the section alignment. */ | 
 |   load_addr += 0x1000; | 
 |   unloaded_dll (NULL, load_addr); | 
 | } | 
 |  | 
 | static void | 
 | suspend_one_thread (thread_info *thread) | 
 | { | 
 |   windows_thread_info *th = (windows_thread_info *) thread_target_data (thread); | 
 |  | 
 |   th->suspend (); | 
 | } | 
 |  | 
 | static void | 
 | fake_breakpoint_event (void) | 
 | { | 
 |   OUTMSG2(("fake_breakpoint_event\n")); | 
 |  | 
 |   windows_process.faked_breakpoint = 1; | 
 |  | 
 |   memset (&windows_process.current_event, 0, | 
 | 	  sizeof (windows_process.current_event)); | 
 |   windows_process.current_event.dwThreadId = windows_process.main_thread_id; | 
 |   windows_process.current_event.dwDebugEventCode = EXCEPTION_DEBUG_EVENT; | 
 |   windows_process.current_event.u.Exception.ExceptionRecord.ExceptionCode | 
 |     = EXCEPTION_BREAKPOINT; | 
 |  | 
 |   for_each_thread (suspend_one_thread); | 
 | } | 
 |  | 
 | /* See nat/windows-nat.h.  */ | 
 |  | 
 | bool | 
 | gdbserver_windows_process::handle_access_violation | 
 |      (const EXCEPTION_RECORD *rec) | 
 | { | 
 |   return false; | 
 | } | 
 |  | 
 | /* A helper function that will, if needed, set | 
 |    'stopped_at_software_breakpoint' on the thread and adjust the | 
 |    PC.  */ | 
 |  | 
 | static void | 
 | maybe_adjust_pc () | 
 | { | 
 |   struct regcache *regcache = get_thread_regcache (current_thread, 1); | 
 |   child_fetch_inferior_registers (regcache, -1); | 
 |  | 
 |   windows_thread_info *th | 
 |     = 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); | 
 |     } | 
 | } | 
 |  | 
 | /* Get the next event from the child.  */ | 
 |  | 
 | static int | 
 | get_child_debug_event (DWORD *continue_status, | 
 | 		       struct target_waitstatus *ourstatus) | 
 | { | 
 |   ptid_t ptid; | 
 |  | 
 |   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 (); | 
 |  | 
 |   DEBUG_EVENT *current_event = &windows_process.current_event; | 
 |  | 
 |   if (windows_process.soft_interrupt_requested) | 
 |     { | 
 |       windows_process.soft_interrupt_requested = 0; | 
 |       fake_breakpoint_event (); | 
 |       goto gotevent; | 
 |     } | 
 |  | 
 |   windows_process.attaching = 0; | 
 |   { | 
 |     gdb::optional<pending_stop> 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; | 
 |       } | 
 |  | 
 |     /* 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 successfully | 
 | 	       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) | 
 |     { | 
 |     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)); | 
 |  | 
 |       /* 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); | 
 |       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); | 
 |  | 
 |       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); | 
 |  | 
 |       if (windows_process.open_process_used) | 
 | 	{ | 
 | 	  CloseHandle (windows_process.handle); | 
 | 	  windows_process.open_process_used = false; | 
 | 	} | 
 |  | 
 |       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)); | 
 |       { | 
 | 	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->set_exited (exit_status); | 
 | 	else | 
 | 	  ourstatus->set_signalled (gdb_signal_from_host (exit_signal)); | 
 |       } | 
 |       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 (! windows_process.child_initialization_done) | 
 | 	break; | 
 |       windows_process.dll_loaded_event (); | 
 |  | 
 |       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 (! windows_process.child_initialization_done) | 
 | 	break; | 
 |       windows_process.handle_unload_dll (); | 
 |       ourstatus->set_loaded (); | 
 |       break; | 
 |  | 
 |     case EXCEPTION_DEBUG_EVENT: | 
 |       OUTMSG2 (("gdbserver: kernel event EXCEPTION_DEBUG_EVENT " | 
 | 		"for pid=%u tid=%x\n", | 
 | 		(unsigned) current_event->dwProcessId, | 
 | 		(unsigned) current_event->dwThreadId)); | 
 |       if (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)); | 
 |       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)); | 
 |       break; | 
 |     } | 
 |  | 
 |   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; | 
 | } | 
 |  | 
 | /* Wait for the inferior process to change state. | 
 |    STATUS will be filled in with a response code to send to GDB. | 
 |    Returns the signal which caused the process to stop. */ | 
 | ptid_t | 
 | win32_process_target::wait (ptid_t ptid, target_waitstatus *ourstatus, | 
 | 			    target_wait_flags options) | 
 | { | 
 |   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 = windows_process.cached_status; | 
 |       windows_process.cached_status.set_ignore (); | 
 |       return debug_event_ptid (&windows_process.current_event); | 
 |     } | 
 |  | 
 |   while (1) | 
 |     { | 
 |       DWORD continue_status; | 
 |       if (!get_child_debug_event (&continue_status, ourstatus)) | 
 | 	continue; | 
 |  | 
 |       switch (ourstatus->kind ()) | 
 | 	{ | 
 | 	case TARGET_WAITKIND_EXITED: | 
 | 	  OUTMSG2 (("Child exited with retcode = %x\n", | 
 | 		    ourstatus->exit_status ())); | 
 | 	  win32_clear_inferiors (); | 
 | 	  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->sig ())); | 
 | 	    maybe_adjust_pc (); | 
 | 	    return debug_event_ptid (&windows_process.current_event); | 
 | 	  } | 
 | 	default: | 
 | 	  OUTMSG (("Ignoring unknown internal event, %d\n", | 
 | 		  ourstatus->kind ())); | 
 | 	  /* fall-through */ | 
 | 	case TARGET_WAITKIND_SPURIOUS: | 
 | 	  /* do nothing, just continue */ | 
 | 	  child_continue (continue_status, | 
 | 			  windows_process.desired_stop_thread_id); | 
 | 	  break; | 
 | 	} | 
 |     } | 
 | } | 
 |  | 
 | /* Fetch registers from the inferior process. | 
 |    If REGNO is -1, fetch all registers; otherwise, fetch at least REGNO.  */ | 
 | void | 
 | win32_process_target::fetch_registers (regcache *regcache, int regno) | 
 | { | 
 |   child_fetch_inferior_registers (regcache, regno); | 
 | } | 
 |  | 
 | /* Store registers to the inferior process. | 
 |    If REGNO is -1, store all registers; otherwise, store at least REGNO.  */ | 
 | void | 
 | win32_process_target::store_registers (regcache *regcache, int regno) | 
 | { | 
 |   child_store_inferior_registers (regcache, regno); | 
 | } | 
 |  | 
 | /* Read memory from the inferior process.  This should generally be | 
 |    called through read_inferior_memory, which handles breakpoint shadowing. | 
 |    Read LEN bytes at MEMADDR into a buffer at MYADDR.  */ | 
 | int | 
 | win32_process_target::read_memory (CORE_ADDR memaddr, unsigned char *myaddr, | 
 | 				   int len) | 
 | { | 
 |   return child_xfer_memory (memaddr, (char *) myaddr, len, 0, 0) != len; | 
 | } | 
 |  | 
 | /* Write memory to the inferior process.  This should generally be | 
 |    called through write_inferior_memory, which handles breakpoint shadowing. | 
 |    Write LEN bytes from the buffer at MYADDR to MEMADDR. | 
 |    Returns 0 on success and errno on failure.  */ | 
 | int | 
 | win32_process_target::write_memory (CORE_ADDR memaddr, | 
 | 				    const unsigned char *myaddr, int len) | 
 | { | 
 |   return child_xfer_memory (memaddr, (char *) myaddr, len, 1, 0) != len; | 
 | } | 
 |  | 
 | /* Send an interrupt request to the inferior process. */ | 
 | void | 
 | win32_process_target::request_interrupt () | 
 | { | 
 |   if (GenerateConsoleCtrlEvent (CTRL_BREAK_EVENT, signal_pid)) | 
 |     return; | 
 |  | 
 |   /* GenerateConsoleCtrlEvent can fail if process id being debugged is | 
 |      not a process group id. | 
 |      Fallback to XP/Vista 'DebugBreakProcess', which generates a | 
 |      breakpoint exception in the interior process.  */ | 
 |  | 
 |   if (DebugBreakProcess (windows_process.handle)) | 
 |     return; | 
 |  | 
 |   /* Last resort, suspend all threads manually.  */ | 
 |   windows_process.soft_interrupt_requested = 1; | 
 | } | 
 |  | 
 | bool | 
 | win32_process_target::supports_hardware_single_step () | 
 | { | 
 |   return true; | 
 | } | 
 |  | 
 | bool | 
 | win32_process_target::supports_qxfer_siginfo () | 
 | { | 
 |   return true; | 
 | } | 
 |  | 
 | /* Write Windows signal info.  */ | 
 |  | 
 | int | 
 | win32_process_target::qxfer_siginfo (const char *annex, | 
 | 				     unsigned char *readbuf, | 
 | 				     unsigned const char *writebuf, | 
 | 				     CORE_ADDR offset, int len) | 
 | { | 
 |   if (windows_process.siginfo_er.ExceptionCode == 0) | 
 |     return -1; | 
 |  | 
 |   if (readbuf == nullptr) | 
 |     return -1; | 
 |  | 
 |   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 > bufsize) | 
 |     len = bufsize - offset; | 
 |  | 
 |   memcpy (readbuf, buf + offset, len); | 
 |  | 
 |   return len; | 
 | } | 
 |  | 
 | bool | 
 | win32_process_target::supports_get_tib_address () | 
 | { | 
 |   return true; | 
 | } | 
 |  | 
 | /* Write Windows OS Thread Information Block address.  */ | 
 |  | 
 | int | 
 | win32_process_target::get_tib_address (ptid_t ptid, CORE_ADDR *addr) | 
 | { | 
 |   windows_thread_info *th; | 
 |   th = windows_process.thread_rec (ptid, DONT_INVALIDATE_CONTEXT); | 
 |   if (th == NULL) | 
 |     return 0; | 
 |   if (addr != NULL) | 
 |     *addr = th->thread_local_base; | 
 |   return 1; | 
 | } | 
 |  | 
 | /* Implementation of the target_ops method "sw_breakpoint_from_kind".  */ | 
 |  | 
 | 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; | 
 |  | 
 | /* Initialize the Win32 backend.  */ | 
 | void | 
 | initialize_low (void) | 
 | { | 
 |   set_target_ops (&the_win32_target); | 
 |   the_low_target.arch_setup (); | 
 |  | 
 |   initialize_loadable (); | 
 | } |