Move gdb/signals.h to common-defs.h
[deliverable/binutils-gdb.git] / gdb / gdbserver / win32-low.c
index d1caa73096016d5eeb3cc8d063bdd0a165241812..2242d5c335e1da94a7bc4eb6aea17596928660d9 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-2014 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 "dll.h"
+#include "hostio.h"
 
 #include <stdint.h>
 #include <windows.h>
@@ -32,7 +33,6 @@
 #include <imagehlp.h>
 #include <tlhelp32.h>
 #include <psapi.h>
-#include <sys/param.h>
 #include <process.h>
 
 #ifndef USE_WIN32API
@@ -79,6 +79,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;
@@ -91,19 +96,24 @@ 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)
 {
-  return ((struct inferior_list_entry*) current_inferior)->id;
+  return current_ptid;
 }
 
 /* The current debug event from WaitForDebugEvent.  */
@@ -221,7 +231,7 @@ child_delete_thread (DWORD pid, DWORD tid)
   ptid_t ptid;
 
   /* If the last thread is exiting, just return.  */
-  if (all_threads.head == all_threads.tail)
+  if (one_inferior_p (&all_threads))
     return;
 
   ptid = ptid_build (pid, tid, 0);
@@ -236,20 +246,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;
@@ -279,21 +298,30 @@ static int
 child_xfer_memory (CORE_ADDR memaddr, char *our, int len,
                   int write, struct target_ops *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
@@ -304,6 +332,10 @@ child_init_thread_list (void)
   for_each_inferior (&all_threads, 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)
 {
@@ -323,9 +355,59 @@ 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
@@ -515,7 +597,7 @@ static int
 win32_create_inferior (char *program, char **program_args)
 {
 #ifndef USE_WIN32API
-  char real_path[MAXPATHLEN];
+  char real_path[PATH_MAX];
   char *orig_path, *new_path, *path_ptr;
 #endif
   BOOL ret;
@@ -546,8 +628,7 @@ win32_create_inferior (char *program, char **program_args)
       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,
-                   MAXPATHLEN);
+  cygwin_conv_path (CCP_POSIX_TO_WIN_A, program, real_path, PATH_MAX);
   program = real_path;
 #endif
 
@@ -898,6 +979,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
@@ -1023,11 +1109,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;
@@ -1035,7 +1124,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,
@@ -1044,181 +1133,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;
-
-  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;
-       }
+/* Handle a DLL load event.
 
-#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';
-
-  /* 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);
-    }
+  char *dll_name;
 
-  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);
 }
@@ -1528,6 +1516,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;
@@ -1539,6 +1529,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;
@@ -1584,6 +1576,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))
@@ -1603,21 +1606,6 @@ win32_wait (ptid_t ptid, struct target_waitstatus *ourstatus, int options)
 
          regcache = get_thread_regcache (current_inferior, 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));
@@ -1793,6 +1781,7 @@ 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,
   win32_stopped_by_watchpoint,
This page took 0.030331 seconds and 4 git commands to generate.