Multi-target support
[deliverable/binutils-gdb.git] / gdb / gdbserver / win32-low.c
index 30fd1e74e91891925a5a191e6639fd931c0a6769..2c4a9b1074b2f857d744b3831204604146395935 100644 (file)
@@ -1,5 +1,5 @@
 /* Low level interface to Windows debugging, for gdbserver.
-   Copyright (C) 2006-2013 Free Software Foundation, Inc.
+   Copyright (C) 2006-2020 Free Software Foundation, Inc.
 
    Contributed by Leo Zayas.  Based on "win32-nat.c" from GDB.
 
 
 #include "server.h"
 #include "regcache.h"
-#include "gdb/signals.h"
 #include "gdb/fileio.h"
 #include "mem-break.h"
 #include "win32-low.h"
 #include "gdbthread.h"
-
-#include <stdint.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"
 
 #ifndef USE_WIN32API
 #include <sys/cygwin.h>
@@ -78,6 +80,11 @@ 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;
@@ -90,26 +97,31 @@ 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);
+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);
 
+static ptid_t win32_wait (ptid_t ptid, struct target_waitstatus *ourstatus,
+                         int options);
 static void win32_resume (struct thread_resume *resume_info, size_t n);
+#ifndef _WIN32_WCE
+static void win32_add_all_dlls (void);
+#endif
 
 /* Get the thread ID from the current selected inferior (the current
    thread).  */
 static ptid_t
-current_inferior_ptid (void)
+current_thread_ptid (void)
 {
-  return ((struct inferior_list_entry*) current_inferior)->id;
+  return current_ptid;
 }
 
 /* The current debug event from WaitForDebugEvent.  */
 static ptid_t
 debug_event_ptid (DEBUG_EVENT *event)
 {
-  return ptid_build (event->dwProcessId, event->dwThreadId, 0);
+  return ptid_t (event->dwProcessId, event->dwThreadId, 0);
 }
 
 /* Get the thread context of the thread associated with TH.  */
@@ -118,7 +130,7 @@ static void
 win32_get_thread_context (win32_thread_info *th)
 {
   memset (&th->context, 0, sizeof (CONTEXT));
-  (*the_low_target.get_thread_context) (th, &current_event);
+  (*the_low_target.get_thread_context) (th);
 #ifdef _WIN32_WCE
   memcpy (&th->base_context, &th->context, sizeof (CONTEXT));
 #endif
@@ -135,30 +147,31 @@ win32_set_thread_context (win32_thread_info *th)
      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 likelly crash the inferior.
+     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)
 #endif
-    (*the_low_target.set_thread_context) (th, &current_event);
+    SetThreadContext (th->h, &th->context);
 }
 
-/* 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)
+/* Set the thread context of the thread associated with TH.  */
+
+static void
+win32_prepare_to_resume (win32_thread_info *th)
 {
-  struct thread_info *thread;
-  win32_thread_info *th;
+  if (the_low_target.prepare_to_resume != NULL)
+    (*the_low_target.prepare_to_resume) (th);
+}
 
-  thread = (struct thread_info *) find_inferior_id (&all_threads, ptid);
-  if (thread == NULL)
-    return NULL;
+/* See win32-low.h.  */
 
-  th = inferior_target_data (thread);
-  if (get_context && th->context.ContextFlags == 0)
+void
+win32_require_context (win32_thread_info *th)
+{
+  if (th->context.ContextFlags == 0)
     {
       if (!th->suspended)
        {
@@ -174,7 +187,20 @@ thread_rec (ptid_t ptid, int get_context)
 
       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)
+{
+  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)
+    win32_require_context (th);
   return th;
 }
 
@@ -183,12 +209,12 @@ static win32_thread_info *
 child_add_thread (DWORD pid, DWORD tid, HANDLE h, void *tlb)
 {
   win32_thread_info *th;
-  ptid_t ptid = ptid_build (pid, tid, 0);
+  ptid_t ptid = ptid_t (pid, tid, 0);
 
   if ((th = thread_rec (ptid, FALSE)))
     return th;
 
-  th = xcalloc (1, sizeof (*th));
+  th = XCNEW (win32_thread_info);
   th->tid = tid;
   th->h = h;
   th->thread_local_base = (CORE_ADDR) (uintptr_t) tlb;
@@ -203,11 +229,11 @@ child_add_thread (DWORD pid, DWORD tid, HANDLE h, void *tlb)
 
 /* Delete a thread from the list of threads.  */
 static void
-delete_thread_info (struct inferior_list_entry *thread)
+delete_thread_info (thread_info *thread)
 {
-  win32_thread_info *th = inferior_target_data ((struct thread_info *) thread);
+  win32_thread_info *th = (win32_thread_info *) thread_target_data (thread);
 
-  remove_thread ((struct thread_info *) thread);
+  remove_thread (thread);
   CloseHandle (th->h);
   free (th);
 }
@@ -216,15 +242,11 @@ delete_thread_info (struct inferior_list_entry *thread)
 static void
 child_delete_thread (DWORD pid, DWORD tid)
 {
-  struct inferior_list_entry *thread;
-  ptid_t ptid;
-
   /* If the last thread is exiting, just return.  */
-  if (all_threads.head == all_threads.tail)
+  if (all_threads.size () == 1)
     return;
 
-  ptid = ptid_build (pid, tid, 0);
-  thread = find_inferior_id (&all_threads, ptid);
+  thread_info *thread = find_thread_ptid (ptid_t (pid, tid));
   if (thread == NULL)
     return;
 
@@ -235,20 +257,29 @@ child_delete_thread (DWORD pid, DWORD tid)
    if the low target has registered a corresponding function.  */
 
 static int
-win32_insert_point (char type, CORE_ADDR addr, int len)
+win32_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));
+}
+
+static int
+win32_insert_point (enum raw_bkpt_type type, CORE_ADDR addr,
+                   int size, struct raw_breakpoint *bp)
 {
   if (the_low_target.insert_point != NULL)
-    return the_low_target.insert_point (type, addr, len);
+    return the_low_target.insert_point (type, addr, size, bp);
   else
     /* Unsupported (see target.h).  */
     return 1;
 }
 
 static int
-win32_remove_point (char type, CORE_ADDR addr, int len)
+win32_remove_point (enum raw_bkpt_type type, CORE_ADDR addr,
+                   int size, struct raw_breakpoint *bp)
 {
   if (the_low_target.remove_point != NULL)
-    return the_low_target.remove_point (type, addr, len);
+    return the_low_target.remove_point (type, addr, size, bp);
   else
     /* Unsupported (see target.h).  */
     return 1;
@@ -276,23 +307,32 @@ win32_stopped_data_address (void)
 /* Transfer memory from/to the debugged process.  */
 static int
 child_xfer_memory (CORE_ADDR memaddr, char *our, int len,
-                  int write, struct target_ops *target)
+                  int write, process_stratum_target *target)
 {
-  SIZE_T done;
+  BOOL success;
+  SIZE_T done = 0;
+  DWORD lasterror = 0;
   uintptr_t addr = (uintptr_t) memaddr;
 
   if (write)
     {
-      WriteProcessMemory (current_process_handle, (LPVOID) addr,
-                         (LPCVOID) our, len, &done);
+      success = WriteProcessMemory (current_process_handle, (LPVOID) addr,
+                                   (LPCVOID) our, len, &done);
+      if (!success)
+       lasterror = GetLastError ();
       FlushInstructionCache (current_process_handle, (LPCVOID) addr, len);
     }
   else
     {
-      ReadProcessMemory (current_process_handle, (LPCVOID) addr, (LPVOID) our,
-                        len, &done);
+      success = ReadProcessMemory (current_process_handle, (LPCVOID) addr,
+                                  (LPVOID) our, len, &done);
+      if (!success)
+       lasterror = GetLastError ();
     }
-  return done;
+  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
@@ -300,9 +340,13 @@ child_xfer_memory (CORE_ADDR memaddr, char *our, int len,
 static void
 child_init_thread_list (void)
 {
-  for_each_inferior (&all_threads, delete_thread_info);
+  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)
 {
@@ -322,39 +366,89 @@ do_initial_child_stuff (HANDLE proch, DWORD pid, int attached)
   proc = add_process (pid, attached);
   proc->tdesc = win32_tdesc;
   child_init_thread_list ();
+  child_initialization_done = 0;
 
   if (the_low_target.initial_stuff != NULL)
     (*the_low_target.initial_stuff) ();
+
+  cached_status.kind = TARGET_WAITKIND_IGNORE;
+
+  /* Flush all currently pending debug events (thread and dll list) up
+     to the initial breakpoint.  */
+  while (1)
+    {
+      struct target_waitstatus status;
+
+      win32_wait (minus_one_ptid, &status, 0);
+
+      /* Note win32_wait doesn't return thread events.  */
+      if (status.kind != TARGET_WAITKIND_LOADED)
+       {
+         cached_status = status;
+         break;
+       }
+
+      {
+       struct thread_resume resume;
+
+       resume.thread = minus_one_ptid;
+       resume.kind = resume_continue;
+       resume.sig = 0;
+
+       win32_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.
+
+     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.  */
+  win32_add_all_dlls ();
+#endif
+
+  child_initialization_done = 1;
 }
 
 /* Resume all artificially suspended threads if we are continuing
    execution.  */
-static int
-continue_one_thread (struct inferior_list_entry *this_thread, void *id_ptr)
+static void
+continue_one_thread (thread_info *thread, int thread_id)
 {
-  struct thread_info *thread = (struct thread_info *) this_thread;
-  int thread_id = * (int *) id_ptr;
-  win32_thread_info *th = inferior_target_data (thread);
+  win32_thread_info *th = (win32_thread_info *) thread_target_data (thread);
 
-  if ((thread_id == -1 || thread_id == th->tid)
-      && th->suspended)
+  if (thread_id == -1 || thread_id == th->tid)
     {
-      if (th->context.ContextFlags)
-       {
-         win32_set_thread_context (th);
-         th->context.ContextFlags = 0;
-       }
+      win32_prepare_to_resume (th);
 
-      if (ResumeThread (th->h) == (DWORD) -1)
+      if (th->suspended)
        {
-         DWORD err = GetLastError ();
-         OUTMSG (("warning: ResumeThread failed in continue_one_thread, "
-                  "(error %d): %s\n", (int) err, strwinerror (err)));
+         if (th->context.ContextFlags)
+           {
+             win32_set_thread_context (th);
+             th->context.ContextFlags = 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->suspended = 0;
     }
-
-  return 0;
 }
 
 static BOOL
@@ -362,7 +456,10 @@ child_continue (DWORD continue_status, int thread_id)
 {
   /* The inferior will only continue after the ContinueDebugEvent
      call.  */
-  find_inferior (&all_threads, continue_one_thread, &thread_id);
+  for_each_thread ([&] (thread_info *thread)
+    {
+      continue_one_thread (thread, thread_id);
+    });
   faked_breakpoint = 0;
 
   if (!ContinueDebugEvent (current_event.dwProcessId,
@@ -378,7 +475,7 @@ static void
 child_fetch_inferior_registers (struct regcache *regcache, int r)
 {
   int regno;
-  win32_thread_info *th = thread_rec (current_inferior_ptid (), TRUE);
+  win32_thread_info *th = thread_rec (current_thread_ptid (), TRUE);
   if (r == -1 || r > NUM_REGS)
     child_fetch_inferior_registers (regcache, NUM_REGS);
   else
@@ -392,7 +489,7 @@ static void
 child_store_inferior_registers (struct regcache *regcache, int r)
 {
   int regno;
-  win32_thread_info *th = thread_rec (current_inferior_ptid (), TRUE);
+  win32_thread_info *th = thread_rec (current_thread_ptid (), TRUE);
   if (r == -1 || r == 0 || r > NUM_REGS)
     child_store_inferior_registers (regcache, NUM_REGS);
   else
@@ -421,7 +518,7 @@ strwinerror (DWORD error)
                               NULL,
                               error,
                               0, /* Default language */
-                              (LPVOID)&msgbuf,
+                              (LPTSTR) &msgbuf,
                               0,
                               NULL);
   if (chars != 0)
@@ -459,10 +556,11 @@ static BOOL
 create_process (const char *program, char *args,
                DWORD flags, PROCESS_INFORMATION *pi)
 {
+  const char *inferior_cwd = get_inferior_cwd ();
   BOOL ret;
 
 #ifdef _WIN32_WCE
-  wchar_t *p, *wprogram, *wargs;
+  wchar_t *p, *wprogram, *wargs, *wcwd = NULL;
   size_t argslen;
 
   wprogram = alloca ((strlen (program) + 1) * sizeof (wchar_t));
@@ -476,6 +574,20 @@ create_process (const char *program, char *args,
   wargs = alloca ((argslen + 1) * sizeof (wchar_t));
   mbstowcs (wargs, args, argslen + 1);
 
+  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 */
@@ -483,7 +595,7 @@ create_process (const char *program, char *args,
                        FALSE,    /* inherit handles, not supported */
                        flags,    /* start flags */
                        NULL,     /* environment, not supported */
-                       NULL,     /* current directory, not supported */
+                       wcwd,     /* current directory */
                        NULL,     /* start info, not supported */
                        pi);      /* proc info */
 #else
@@ -496,7 +608,10 @@ create_process (const char *program, char *args,
                        TRUE,     /* inherit handles */
                        flags,    /* start flags */
                        NULL,     /* environment */
-                       NULL,     /* current directory */
+                       /* current directory */
+                       (inferior_cwd == NULL
+                        ? NULL
+                        : gdb_tilde_expand (inferior_cwd).c_str()),
                        &si,      /* start info */
                        pi);      /* proc info */
 #endif
@@ -505,25 +620,25 @@ create_process (const char *program, char *args,
 }
 
 /* Start a new process.
-   PROGRAM is a path to the program to execute.
-   ARGS is a standard NULL-terminated array of arguments,
-   to be passed to the inferior as ``argv''.
+   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.  */
 static int
-win32_create_inferior (char *program, char **program_args)
+win32_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;
-  char *args;
-  int argslen;
-  int argc;
   PROCESS_INFORMATION pi;
   DWORD err;
+  std::string str_program_args = stringify_argv (program_args);
+  char *args = (char *) str_program_args.c_str ();
 
   /* win32_wait needs to know we're not attaching.  */
   attaching = 0;
@@ -539,8 +654,8 @@ win32_create_inferior (char *program, char **program_args)
   if (path_ptr)
     {
       int size = cygwin_conv_path_list (CCP_POSIX_TO_WIN_A, path_ptr, NULL, 0);
-      orig_path = alloca (strlen (path_ptr) + 1);
-      new_path = alloca (size);
+      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);
@@ -549,18 +664,6 @@ win32_create_inferior (char *program, char **program_args)
   program = real_path;
 #endif
 
-  argslen = 1;
-  for (argc = 1; program_args[argc]; argc++)
-    argslen += strlen (program_args[argc]) + 1;
-  args = alloca (argslen);
-  args[0] = '\0';
-  for (argc = 1; program_args[argc]; argc++)
-    {
-      /* FIXME: Can we do better about quoting?  How does Cygwin
-        handle this?  */
-      strcat (args, " ");
-      strcat (args, program_args[argc]);
-    }
   OUTMSG2 (("Command line is \"%s\"\n", args));
 
 #ifdef CREATE_NEW_PROCESS_GROUP
@@ -571,7 +674,7 @@ win32_create_inferior (char *program, char **program_args)
   err = GetLastError ();
   if (!ret && err == ERROR_FILE_NOT_FOUND)
     {
-      char *exename = alloca (strlen (program) + 5);
+      char *exename = (char *) alloca (strlen (program) + 5);
       strcat (strcpy (exename, program), ".exe");
       ret = create_process (exename, args, flags, &pi);
       err = GetLastError ();
@@ -601,6 +704,10 @@ win32_create_inferior (char *program, char **program_args)
 
   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 = win32_wait (ptid_t (current_process_id), &cs.last_status, 0);
+
   return current_process_id;
 }
 
@@ -644,7 +751,7 @@ win32_attach (unsigned long pid)
 
 /* Handle OUTPUT_DEBUG_STRING_EVENT from child process.  */
 static void
-handle_output_debug_string (struct target_waitstatus *ourstatus)
+handle_output_debug_string (void)
 {
 #define READ_BUFFER_LEN 1024
   CORE_ADDR addr;
@@ -674,7 +781,7 @@ handle_output_debug_string (struct target_waitstatus *ourstatus)
        return;
     }
 
-  if (strncmp (s, "cYg", 3) != 0)
+  if (!startswith (s, "cYg"))
     {
       if (!server_waiting)
        {
@@ -693,19 +800,15 @@ win32_clear_inferiors (void)
   if (current_process_handle != NULL)
     CloseHandle (current_process_handle);
 
-  for_each_inferior (&all_threads, delete_thread_info);
+  for_each_thread (delete_thread_info);
   clear_inferiors ();
 }
 
-/* Kill all inferiors.  */
+/* Implementation of target_ops::kill.  */
+
 static int
-win32_kill (int pid)
+win32_kill (process_info *process)
 {
-  struct process_info *process;
-
-  if (current_process_handle == NULL)
-    return -1;
-
   TerminateProcess (current_process_handle, 0);
   for (;;)
     {
@@ -716,24 +819,20 @@ win32_kill (int pid)
       if (current_event.dwDebugEventCode == EXIT_PROCESS_DEBUG_EVENT)
        break;
       else if (current_event.dwDebugEventCode == OUTPUT_DEBUG_STRING_EVENT)
-       {
-         struct target_waitstatus our_status = { 0 };
-         handle_output_debug_string (&our_status);
-       }
+       handle_output_debug_string ();
     }
 
   win32_clear_inferiors ();
 
-  process = find_process_pid (pid);
   remove_process (process);
   return 0;
 }
 
-/* Detach from inferior PID.  */
+/* Implementation of target_ops::detach.  */
+
 static int
-win32_detach (int pid)
+win32_detach (process_info *process)
 {
-  struct process_info *process;
   winapi_DebugActiveProcessStop DebugActiveProcessStop = NULL;
   winapi_DebugSetProcessKillOnExit DebugSetProcessKillOnExit = NULL;
 #ifdef _WIN32_WCE
@@ -760,7 +859,6 @@ win32_detach (int pid)
     return -1;
 
   DebugSetProcessKillOnExit (FALSE);
-  process = find_process_pid (pid);
   remove_process (process);
 
   win32_clear_inferiors ();
@@ -773,7 +871,8 @@ win32_mourn (struct process_info *process)
   remove_process (process);
 }
 
-/* Wait for inferiors to end.  */
+/* Implementation of target_ops::join.  */
+
 static void
 win32_join (int pid)
 {
@@ -789,15 +888,9 @@ win32_join (int pid)
 static int
 win32_thread_alive (ptid_t ptid)
 {
-  int res;
-
   /* Our thread list is reliable; don't bother to poll target
      threads.  */
-  if (find_inferior_id (&all_threads, ptid) != NULL)
-    res = 1;
-  else
-    res = 0;
-  return res;
+  return find_thread_ptid (ptid) != NULL;
 }
 
 /* Resume the inferior process.  RESUME_INFO describes how we want
@@ -815,7 +908,7 @@ win32_resume (struct thread_resume *resume_info, size_t n)
   /* This handles the very limited set of resume packets that GDB can
      currently produce.  */
 
-  if (n == 1 && ptid_equal (resume_info[0].thread, minus_one_ptid))
+  if (n == 1 && resume_info[0].thread == minus_one_ptid)
     tid = -1;
   else if (n > 1)
     tid = -1;
@@ -824,14 +917,14 @@ win32_resume (struct thread_resume *resume_info, size_t n)
        the Windows resume code do the right thing for thread switching.  */
     tid = current_event.dwThreadId;
 
-  if (!ptid_equal (resume_info[0].thread, minus_one_ptid))
+  if (resume_info[0].thread != minus_one_ptid)
     {
-      sig = resume_info[0].sig;
+      sig = gdb_signal_from_host (resume_info[0].sig);
       step = resume_info[0].kind == resume_step;
     }
   else
     {
-      sig = 0;
+      sig = GDB_SIGNAL_0;
       step = 0;
     }
 
@@ -839,12 +932,14 @@ win32_resume (struct thread_resume *resume_info, size_t n)
     {
       if (current_event.dwDebugEventCode != EXCEPTION_DEBUG_EVENT)
        {
-         OUTMSG (("Cannot continue with signal %d here.\n", sig));
+         OUTMSG (("Cannot continue with signal %s here.\n",
+                  gdb_signal_to_string (sig)));
        }
       else if (sig == last_sig)
        continue_status = DBG_EXCEPTION_NOT_HANDLED;
       else
-       OUTMSG (("Can only continue with recieved signal %d.\n", last_sig));
+       OUTMSG (("Can only continue with received signal %s.\n",
+                gdb_signal_to_string (last_sig)));
     }
 
   last_sig = GDB_SIGNAL_0;
@@ -854,6 +949,8 @@ win32_resume (struct thread_resume *resume_info, size_t n)
   th = thread_rec (ptid, FALSE);
   if (th)
     {
+      win32_prepare_to_resume (th);
+
       if (th->context.ContextFlags)
        {
          /* Move register values from the inferior into the thread
@@ -896,6 +993,11 @@ win32_add_one_solib (const char *name, CORE_ADDR load_addr)
   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
+     of the file header and the section alignment. */
+  load_addr += 0x1000;
+
   if (h == INVALID_HANDLE_VALUE)
     strcpy (buf, name);
   else
@@ -975,7 +1077,7 @@ get_image_name (HANDLE h, void *address, int unicode)
     ReadProcessMemory (h, address_ptr, buf, len, &done);
   else
     {
-      WCHAR *unicode_address = (WCHAR *) alloca (len * sizeof (WCHAR));
+      WCHAR *unicode_address = XALLOCAVEC (WCHAR, len);
       ReadProcessMemory (h, address_ptr, unicode_address, len * sizeof (WCHAR),
                         &done);
 
@@ -1021,11 +1123,14 @@ load_psapi (void)
          && win32_GetModuleFileNameExA != NULL);
 }
 
-static int
-psapi_get_dll_name (LPVOID BaseAddress, char *dll_name_ret)
+#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)
 {
-  DWORD len;
-  MODULEINFO mi;
   size_t i;
   HMODULE dh_buf[1];
   HMODULE *DllHandle = dh_buf;
@@ -1033,7 +1138,7 @@ psapi_get_dll_name (LPVOID BaseAddress, char *dll_name_ret)
   BOOL ok;
 
   if (!load_psapi ())
-    goto failed;
+    return;
 
   cbNeeded = 0;
   ok = (*win32_EnumProcessModules) (current_process_handle,
@@ -1042,181 +1147,80 @@ psapi_get_dll_name (LPVOID BaseAddress, char *dll_name_ret)
                                    &cbNeeded);
 
   if (!ok || !cbNeeded)
-    goto failed;
+    return;
 
   DllHandle = (HMODULE *) alloca (cbNeeded);
   if (!DllHandle)
-    goto failed;
+    return;
 
   ok = (*win32_EnumProcessModules) (current_process_handle,
                                    DllHandle,
                                    cbNeeded,
                                    &cbNeeded);
   if (!ok)
-    goto failed;
+    return;
 
-  for (i = 0; i < ((size_t) cbNeeded / sizeof (HMODULE)); i++)
+  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)))
-       {
-         DWORD err = GetLastError ();
-         error ("Can't get module info: (error %d): %s\n",
-                (int) err, strwinerror (err));
-       }
-
-      if (mi.lpBaseOfDll == BaseAddress)
-       {
-         len = (*win32_GetModuleFileNameExA) (current_process_handle,
-                                              DllHandle[i],
-                                              dll_name_ret,
-                                              MAX_PATH);
-         if (len == 0)
-           {
-             DWORD err = GetLastError ();
-             error ("Error getting dll name: (error %d): %s\n",
-                    (int) err, strwinerror (err));
-           }
-         return 1;
-       }
+       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);
     }
-
-failed:
-  dll_name_ret[0] = '\0';
-  return 0;
 }
+#endif
 
 typedef HANDLE (WINAPI *winapi_CreateToolhelp32Snapshot) (DWORD, DWORD);
 typedef BOOL (WINAPI *winapi_Module32First) (HANDLE, LPMODULEENTRY32);
 typedef BOOL (WINAPI *winapi_Module32Next) (HANDLE, LPMODULEENTRY32);
 
-static winapi_CreateToolhelp32Snapshot win32_CreateToolhelp32Snapshot;
-static winapi_Module32First win32_Module32First;
-static winapi_Module32Next win32_Module32Next;
-#ifdef _WIN32_WCE
-typedef BOOL (WINAPI *winapi_CloseToolhelp32Snapshot) (HANDLE);
-static winapi_CloseToolhelp32Snapshot win32_CloseToolhelp32Snapshot;
-#endif
-
-static BOOL
-load_toolhelp (void)
-{
-  static int toolhelp_loaded = 0;
-  static HMODULE dll = NULL;
+/* Handle a DLL load event.
 
-  if (!toolhelp_loaded)
-    {
-      toolhelp_loaded = 1;
-#ifndef _WIN32_WCE
-      dll = GetModuleHandle (_T("KERNEL32.DLL"));
-#else
-      dll = LoadLibrary (L"TOOLHELP.DLL");
-#endif
-      if (!dll)
-       return FALSE;
-
-      win32_CreateToolhelp32Snapshot =
-       GETPROCADDRESS (dll, CreateToolhelp32Snapshot);
-      win32_Module32First = GETPROCADDRESS (dll, Module32First);
-      win32_Module32Next = GETPROCADDRESS (dll, Module32Next);
-#ifdef _WIN32_WCE
-      win32_CloseToolhelp32Snapshot =
-       GETPROCADDRESS (dll, CloseToolhelp32Snapshot);
-#endif
-    }
-
-  return (win32_CreateToolhelp32Snapshot != NULL
-         && win32_Module32First != NULL
-         && win32_Module32Next != NULL
-#ifdef _WIN32_WCE
-         && win32_CloseToolhelp32Snapshot != NULL
-#endif
-         );
-}
-
-static int
-toolhelp_get_dll_name (LPVOID BaseAddress, char *dll_name_ret)
-{
-  HANDLE snapshot_module;
-  MODULEENTRY32 modEntry = { sizeof (MODULEENTRY32) };
-  int found = 0;
-
-  if (!load_toolhelp ())
-    return 0;
-
-  snapshot_module = win32_CreateToolhelp32Snapshot (TH32CS_SNAPMODULE,
-                                                   current_event.dwProcessId);
-  if (snapshot_module == INVALID_HANDLE_VALUE)
-    return 0;
-
-  /* Ignore the first module, which is the exe.  */
-  if (win32_Module32First (snapshot_module, &modEntry))
-    while (win32_Module32Next (snapshot_module, &modEntry))
-      if (modEntry.modBaseAddr == BaseAddress)
-       {
-#ifdef UNICODE
-         wcstombs (dll_name_ret, modEntry.szExePath, MAX_PATH + 1);
-#else
-         strcpy (dll_name_ret, modEntry.szExePath);
-#endif
-         found = 1;
-         break;
-       }
-
-#ifdef _WIN32_WCE
-  win32_CloseToolhelp32Snapshot (snapshot_module);
-#else
-  CloseHandle (snapshot_module);
-#endif
-  return found;
-}
+   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 = &current_event.u.LoadDll;
-  char dll_buf[MAX_PATH + 1];
-  char *dll_name = NULL;
-  CORE_ADDR load_addr;
-
-  dll_buf[0] = dll_buf[sizeof (dll_buf) - 1] = '\0';
+  char *dll_name;
 
-  /* Windows does not report the image name of the dlls in the debug
-     event on attaches.  We resort to iterating over the list of
-     loaded dlls looking for a match by image base.  */
-  if (!psapi_get_dll_name (event->lpBaseOfDll, dll_buf))
-    {
-      if (!server_waiting)
-       /* On some versions of Windows and Windows CE, we can't create
-          toolhelp snapshots while the inferior is stopped in a
-          LOAD_DLL_DEBUG_EVENT due to a dll load, but we can while
-          Windows is reporting the already loaded dlls.  */
-       toolhelp_get_dll_name (event->lpBaseOfDll, dll_buf);
-    }
-
-  dll_name = dll_buf;
-
-  if (*dll_name == '\0')
-    dll_name = get_image_name (current_process_handle,
-                              event->lpImageName, event->fUnicode);
+  dll_name = get_image_name (current_process_handle,
+                            event->lpImageName, event->fUnicode);
   if (!dll_name)
     return;
 
-  /* 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 = (CORE_ADDR) (uintptr_t) event->lpBaseOfDll + 0x1000;
-  win32_add_one_solib (dll_name, load_addr);
+  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).  */
+
 static void
 handle_unload_dll (void)
 {
   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);
 }
@@ -1330,10 +1334,9 @@ handle_exception (struct target_waitstatus *ourstatus)
 
 
 static void
-suspend_one_thread (struct inferior_list_entry *entry)
+suspend_one_thread (thread_info *thread)
 {
-  struct thread_info *thread = (struct thread_info *) entry;
-  win32_thread_info *th = inferior_target_data (thread);
+  win32_thread_info *th = (win32_thread_info *) thread_target_data (thread);
 
   if (!th->suspended)
     {
@@ -1361,7 +1364,7 @@ fake_breakpoint_event (void)
   current_event.u.Exception.ExceptionRecord.ExceptionCode
     = EXCEPTION_BREAKPOINT;
 
-  for_each_inferior (&all_threads, suspend_one_thread);
+  for_each_thread (suspend_one_thread);
 }
 
 #ifdef _WIN32_WCE
@@ -1424,7 +1427,7 @@ get_child_debug_event (struct target_waitstatus *ourstatus)
   else
 #endif
     {
-      /* Keep the wait time low enough for confortable remote
+      /* Keep the wait time low enough for comfortable remote
         interruption, but high enough so gdbserver doesn't become a
         bottleneck.  */
       if (!WaitForDebugEvent (&current_event, 250))
@@ -1471,7 +1474,7 @@ get_child_debug_event (struct target_waitstatus *ourstatus)
       child_delete_thread (current_event.dwProcessId,
                           current_event.dwThreadId);
 
-      current_inferior = (struct thread_info *) all_threads.head;
+      current_thread = get_first_thread ();
       return 1;
 
     case CREATE_PROCESS_DEBUG_EVENT:
@@ -1484,16 +1487,12 @@ get_child_debug_event (struct target_waitstatus *ourstatus)
       current_process_handle = current_event.u.CreateProcessInfo.hProcess;
       main_thread_id = current_event.dwThreadId;
 
-      ourstatus->kind = TARGET_WAITKIND_EXECD;
-      ourstatus->value.execd_pathname = "Main executable";
-
       /* Add the main thread.  */
       child_add_thread (current_event.dwProcessId,
                        main_thread_id,
                        current_event.u.CreateProcessInfo.hThread,
                        current_event.u.CreateProcessInfo.lpThreadLocalBase);
 
-      ourstatus->value.related_pid = debug_event_ptid (&current_event);
 #ifdef _WIN32_WCE
       if (!attaching)
        {
@@ -1513,8 +1512,24 @@ get_child_debug_event (struct target_waitstatus *ourstatus)
                "for pid=%u tid=%x\n",
                (unsigned) current_event.dwProcessId,
                (unsigned) current_event.dwThreadId));
-      ourstatus->kind = TARGET_WAITKIND_EXITED;
-      ourstatus->value.integer = 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;
+         }
+       else
+         {
+           ourstatus->kind = TARGET_WAITKIND_SIGNALLED;
+           ourstatus->value.sig = gdb_signal_from_host (exit_signal);
+         }
+      }
       child_continue (DBG_CONTINUE, -1);
       CloseHandle (current_process_handle);
       current_process_handle = NULL;
@@ -1526,6 +1541,8 @@ get_child_debug_event (struct target_waitstatus *ourstatus)
                (unsigned) current_event.dwProcessId,
                (unsigned) current_event.dwThreadId));
       CloseHandle (current_event.u.LoadDll.hFile);
+      if (! child_initialization_done)
+       break;
       handle_load_dll ();
 
       ourstatus->kind = TARGET_WAITKIND_LOADED;
@@ -1537,6 +1554,8 @@ get_child_debug_event (struct target_waitstatus *ourstatus)
                "for pid=%u tid=%x\n",
                (unsigned) current_event.dwProcessId,
                (unsigned) current_event.dwThreadId));
+      if (! child_initialization_done)
+       break;
       handle_unload_dll ();
       ourstatus->kind = TARGET_WAITKIND_LOADED;
       ourstatus->value.sig = GDB_SIGNAL_TRAP;
@@ -1556,7 +1575,7 @@ get_child_debug_event (struct target_waitstatus *ourstatus)
                "for pid=%u tid=%x\n",
                (unsigned) current_event.dwProcessId,
                (unsigned) current_event.dwThreadId));
-      handle_output_debug_string (ourstatus);
+      handle_output_debug_string ();
       break;
 
     default:
@@ -1569,8 +1588,7 @@ get_child_debug_event (struct target_waitstatus *ourstatus)
     }
 
   ptid = debug_event_ptid (&current_event);
-  current_inferior =
-    (struct thread_info *) find_inferior_id (&all_threads, ptid);
+  current_thread = find_thread_ptid (ptid);
   return 1;
 }
 
@@ -1582,6 +1600,17 @@ win32_wait (ptid_t ptid, struct target_waitstatus *ourstatus, int options)
 {
   struct regcache *regcache;
 
+  if (cached_status.kind != TARGET_WAITKIND_IGNORE)
+    {
+      /* The core always does a wait after creating the inferior, and
+        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 (&current_event);
+    }
+
   while (1)
     {
       if (!get_child_debug_event (ourstatus))
@@ -1593,35 +1622,20 @@ win32_wait (ptid_t ptid, struct target_waitstatus *ourstatus, int options)
          OUTMSG2 (("Child exited with retcode = %x\n",
                    ourstatus->value.integer));
          win32_clear_inferiors ();
-         return pid_to_ptid (current_event.dwProcessId);
+         return ptid_t (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_inferior, 1);
+         regcache = get_thread_regcache (current_thread, 1);
          child_fetch_inferior_registers (regcache, -1);
-
-         if (ourstatus->kind == TARGET_WAITKIND_LOADED
-             && !server_waiting)
-           {
-             /* When gdb connects, we want to be stopped at the
-                initial breakpoint, not in some dll load event.  */
-             child_continue (DBG_CONTINUE, -1);
-             break;
-           }
-
-         /* We don't expose _LOADED events to gdbserver core.  See
-            the `dlls_changed' global.  */
-         if (ourstatus->kind == TARGET_WAITKIND_LOADED)
-           ourstatus->kind = TARGET_WAITKIND_STOPPED;
-
          return debug_event_ptid (&current_event);
        default:
          OUTMSG (("Ignoring unknown internal event, %d\n", ourstatus->kind));
          /* fall-through */
        case TARGET_WAITKIND_SPURIOUS:
-       case TARGET_WAITKIND_EXECD:
          /* do nothing, just continue */
          child_continue (DBG_CONTINUE, -1);
          break;
@@ -1772,8 +1786,18 @@ win32_get_tib_address (ptid_t ptid, CORE_ADDR *addr)
   return 1;
 }
 
-static struct target_ops win32_target_ops = {
+/* Implementation of the target_ops method "sw_breakpoint_from_kind".  */
+
+static const gdb_byte *
+win32_sw_breakpoint_from_kind (int kind, int *size)
+{
+  *size = the_low_target.breakpoint_len;
+  return the_low_target.breakpoint;
+}
+
+static process_stratum_target win32_target_ops = {
   win32_create_inferior,
+  NULL,  /* post_create_inferior */
   win32_attach,
   win32_kill,
   win32_detach,
@@ -1791,13 +1815,18 @@ static struct target_ops win32_target_ops = {
   NULL, /* lookup_symbols */
   win32_request_interrupt,
   NULL, /* read_auxv */
+  win32_supports_z_point_type,
   win32_insert_point,
   win32_remove_point,
+  NULL, /* stopped_by_sw_breakpoint */
+  NULL, /* supports_stopped_by_sw_breakpoint */
+  NULL, /* stopped_by_hw_breakpoint */
+  NULL, /* supports_stopped_by_hw_breakpoint */
+  target_can_do_hardware_single_step,
   win32_stopped_by_watchpoint,
   win32_stopped_data_address,
   NULL, /* read_offsets */
   NULL, /* get_tls_address */
-  NULL, /* qxfer_spu */
 #ifdef _WIN32_WCE
   wince_hostio_last_error,
 #else
@@ -1809,6 +1838,10 @@ static struct target_ops win32_target_ops = {
   NULL, /* async */
   NULL, /* start_non_stop */
   NULL, /* supports_multi_process */
+  NULL, /* supports_fork_events */
+  NULL, /* supports_vfork_events */
+  NULL, /* supports_exec_events */
+  NULL, /* handle_new_gdb_connection */
   NULL, /* handle_monitor_command */
   NULL, /* core_of_thread */
   NULL, /* read_loadmap */
@@ -1817,7 +1850,27 @@ static struct target_ops win32_target_ops = {
   NULL, /* read_pc */
   NULL, /* write_pc */
   NULL, /* thread_stopped */
-  win32_get_tib_address
+  win32_get_tib_address,
+  NULL, /* pause_all */
+  NULL, /* unpause_all */
+  NULL, /* stabilize_threads */
+  NULL, /* install_fast_tracepoint_jump_pad */
+  NULL, /* emit_ops */
+  NULL, /* supports_disable_randomization */
+  NULL, /* get_min_fast_tracepoint_insn_len */
+  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,
 };
 
 /* Initialize the Win32 backend.  */
@@ -1825,8 +1878,5 @@ void
 initialize_low (void)
 {
   set_target_ops (&win32_target_ops);
-  if (the_low_target.breakpoint != NULL)
-    set_breakpoint_data (the_low_target.breakpoint,
-                        the_low_target.breakpoint_len);
   the_low_target.arch_setup ();
 }
This page took 0.040657 seconds and 4 git commands to generate.