* mem-break.c (struct raw_breakpoint): New field shlib_disabled.
[binutils-gdb.git] / gdb / gdbserver / win32-low.c
index 1d7c2034683e2380b158b6b60838a0cc2933ad4c..904d6149eee9e25d079a818290f3492bb8cb923f 100644 (file)
@@ -1,5 +1,5 @@
 /* Low level interface to Windows debugging, for gdbserver.
-   Copyright (C) 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
+   Copyright (C) 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
 
    Contributed by Leo Zayas.  Based on "win32-nat.c" from GDB.
 
 #include <sys/cygwin.h>
 #endif
 
-#define LOG 0
+#define OUTMSG(X) do { printf X; fflush (stderr); } while (0)
 
-#define OUTMSG(X) do { printf X; fflush (stdout); } while (0)
-#if LOG
-#define OUTMSG2(X) do { printf X; fflush (stdout); } while (0)
-#else
-#define OUTMSG2(X) do ; while (0)
-#endif
+#define OUTMSG2(X) \
+  do                                           \
+    {                                          \
+      if (debug_threads)                       \
+       {                                       \
+         printf X;                             \
+         fflush (stderr);                      \
+       }                                       \
+    } while (0)
 
 #ifndef _T
 #define _T(x) TEXT (x)
@@ -94,11 +97,17 @@ static void win32_resume (struct thread_resume *resume_info, size_t n);
 
 /* Get the thread ID from the current selected inferior (the current
    thread).  */
-static DWORD
-current_inferior_tid (void)
+static ptid_t
+current_inferior_ptid (void)
+{
+  return ((struct inferior_list_entry*) current_inferior)->id;
+}
+
+/* The current debug event from WaitForDebugEvent.  */
+static ptid_t
+debug_event_ptid (DEBUG_EVENT *event)
 {
-  win32_thread_info *th = inferior_target_data (current_inferior);
-  return th->tid;
+  return ptid_build (event->dwProcessId, event->dwThreadId, 0);
 }
 
 /* Get the thread context of the thread associated with TH.  */
@@ -137,12 +146,12 @@ win32_set_thread_context (win32_thread_info *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 (DWORD id, int get_context)
+thread_rec (ptid_t ptid, int get_context)
 {
   struct thread_info *thread;
   win32_thread_info *th;
 
-  thread = (struct thread_info *) find_inferior_id (&all_threads, id);
+  thread = (struct thread_info *) find_inferior_id (&all_threads, ptid);
   if (thread == NULL)
     return NULL;
 
@@ -169,20 +178,21 @@ thread_rec (DWORD id, int get_context)
 
 /* Add a thread to the thread list.  */
 static win32_thread_info *
-child_add_thread (DWORD tid, HANDLE h)
+child_add_thread (DWORD pid, DWORD tid, HANDLE h)
 {
   win32_thread_info *th;
+  ptid_t ptid = ptid_build (pid, tid, 0);
 
-  if ((th = thread_rec (tid, FALSE)))
+  if ((th = thread_rec (ptid, FALSE)))
     return th;
 
   th = xcalloc (1, sizeof (*th));
   th->tid = tid;
   th->h = h;
 
-  add_thread (tid, th, (unsigned int) tid);
+  add_thread (ptid, th);
   set_inferior_regcache_data ((struct thread_info *)
-                             find_inferior_id (&all_threads, tid),
+                             find_inferior_id (&all_threads, ptid),
                              new_register_cache ());
 
   if (the_low_target.thread_added != NULL)
@@ -204,21 +214,65 @@ delete_thread_info (struct inferior_list_entry *thread)
 
 /* Delete a thread from the list of threads.  */
 static void
-child_delete_thread (DWORD id)
+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)
     return;
 
-  thread = find_inferior_id (&all_threads, id);
+  ptid = ptid_build (pid, tid, 0);
+  thread = find_inferior_id (&all_threads, ptid);
   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.  */
+
+static int
+win32_insert_point (char type, CORE_ADDR addr, int len)
+{
+  if (the_low_target.insert_point != NULL)
+    return the_low_target.insert_point (type, addr, len);
+  else
+    /* Unsupported (see target.h).  */
+    return 1;
+}
+
+static int
+win32_remove_point (char type, CORE_ADDR addr, int len)
+{
+  if (the_low_target.remove_point != NULL)
+    return the_low_target.remove_point (type, addr, len);
+  else
+    /* Unsupported (see target.h).  */
+    return 1;
+}
+
+static int
+win32_stopped_by_watchpoint (void)
+{
+  if (the_low_target.stopped_by_watchpoint != NULL)
+    return the_low_target.stopped_by_watchpoint ();
+  else
+    return 0;
+}
+
+static CORE_ADDR
+win32_stopped_data_address (void)
+{
+  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,
@@ -250,7 +304,7 @@ child_init_thread_list (void)
 }
 
 static void
-do_initial_child_stuff (HANDLE proch, DWORD pid)
+do_initial_child_stuff (HANDLE proch, DWORD pid, int attached)
 {
   last_sig = TARGET_SIGNAL_0;
 
@@ -263,6 +317,7 @@ do_initial_child_stuff (HANDLE proch, DWORD pid)
 
   memset (&current_event, 0, sizeof (current_event));
 
+  add_process (pid, attached);
   child_init_thread_list ();
 
   if (the_low_target.initial_stuff != NULL)
@@ -317,29 +372,29 @@ child_continue (DWORD continue_status, int thread_id)
 
 /* Fetch register(s) from the current thread context.  */
 static void
-child_fetch_inferior_registers (int r)
+child_fetch_inferior_registers (struct regcache *regcache, int r)
 {
   int regno;
-  win32_thread_info *th = thread_rec (current_inferior_tid (), TRUE);
-  if (r == -1 || r == 0 || r > NUM_REGS)
-    child_fetch_inferior_registers (NUM_REGS);
+  win32_thread_info *th = thread_rec (current_inferior_ptid (), TRUE);
+  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) (th, 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 (int r)
+child_store_inferior_registers (struct regcache *regcache, int r)
 {
   int regno;
-  win32_thread_info *th = thread_rec (current_inferior_tid (), TRUE);
+  win32_thread_info *th = thread_rec (current_inferior_ptid (), TRUE);
   if (r == -1 || r == 0 || r > NUM_REGS)
-    child_store_inferior_registers (NUM_REGS);
+    child_store_inferior_registers (regcache, NUM_REGS);
   else
     for (regno = 0; regno < r; regno++)
-      (*the_low_target.store_inferior_register) (th, regno);
+      (*the_low_target.store_inferior_register) (regcache, th, regno);
 }
 
 /* Map the Windows error number in ERROR to a locale-dependent error
@@ -540,7 +595,7 @@ win32_create_inferior (char *program, char **program_args)
   CloseHandle (pi.hThread);
 #endif
 
-  do_initial_child_stuff (pi.hProcess, pi.dwProcessId);
+  do_initial_child_stuff (pi.hProcess, pi.dwProcessId, 0);
 
   return current_process_id;
 }
@@ -571,7 +626,7 @@ win32_attach (unsigned long pid)
 
          /* win32_wait needs to know we're attaching.  */
          attaching = 1;
-         do_initial_child_stuff (h, pid);
+         do_initial_child_stuff (h, pid, 1);
          return 0;
        }
 
@@ -639,11 +694,13 @@ win32_clear_inferiors (void)
 }
 
 /* Kill all inferiors.  */
-static void
-win32_kill (void)
+static int
+win32_kill (int pid)
 {
+  struct process_info *process;
+
   if (current_process_handle == NULL)
-    return;
+    return -1;
 
   TerminateProcess (current_process_handle, 0);
   for (;;)
@@ -662,12 +719,17 @@ win32_kill (void)
     }
 
   win32_clear_inferiors ();
+
+  process = find_process_pid (pid);
+  remove_process (process);
+  return 0;
 }
 
-/* Detach from all inferiors.  */
+/* Detach from inferior PID.  */
 static int
-win32_detach (void)
+win32_detach (int pid)
 {
+  struct process_info *process;
   winapi_DebugActiveProcessStop DebugActiveProcessStop = NULL;
   winapi_DebugSetProcessKillOnExit DebugSetProcessKillOnExit = NULL;
 #ifdef _WIN32_WCE
@@ -684,7 +746,7 @@ win32_detach (void)
 
   {
     struct thread_resume resume;
-    resume.thread = -1;
+    resume.thread = minus_one_ptid;
     resume.kind = resume_continue;
     resume.sig = 0;
     win32_resume (&resume, 1);
@@ -694,6 +756,8 @@ win32_detach (void)
     return -1;
 
   DebugSetProcessKillOnExit (FALSE);
+  process = find_process_pid (pid);
+  remove_process (process);
 
   win32_clear_inferiors ();
   return 0;
@@ -701,11 +765,9 @@ win32_detach (void)
 
 /* Wait for inferiors to end.  */
 static void
-win32_join (void)
+win32_join (int pid)
 {
-  extern unsigned long signal_pid;
-
-  HANDLE h = OpenProcess (PROCESS_ALL_ACCESS, FALSE, signal_pid);
+  HANDLE h = OpenProcess (PROCESS_ALL_ACCESS, FALSE, pid);
   if (h != NULL)
     {
       WaitForSingleObject (h, INFINITE);
@@ -715,13 +777,13 @@ win32_join (void)
 
 /* Return 1 iff the thread with thread ID TID is alive.  */
 static int
-win32_thread_alive (unsigned long tid)
+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, tid) != NULL)
+  if (find_inferior_id (&all_threads, ptid) != NULL)
     res = 1;
   else
     res = 0;
@@ -738,11 +800,12 @@ win32_resume (struct thread_resume *resume_info, size_t n)
   int step;
   win32_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 == -1)
+  if (n == 1 && ptid_equal (resume_info[0].thread, minus_one_ptid))
     tid = -1;
   else if (n > 1)
     tid = -1;
@@ -751,7 +814,7 @@ 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 (resume_info[0].thread != -1)
+  if (!ptid_equal (resume_info[0].thread, minus_one_ptid))
     {
       sig = resume_info[0].sig;
       step = resume_info[0].kind == resume_step;
@@ -777,7 +840,8 @@ win32_resume (struct thread_resume *resume_info, size_t n)
   last_sig = TARGET_SIGNAL_0;
 
   /* Get context for the currently selected thread.  */
-  th = thread_rec (current_event.dwThreadId, FALSE);
+  ptid = debug_event_ptid (&current_event);
+  th = thread_rec (ptid, FALSE);
   if (th)
     {
       if (th->context.ContextFlags)
@@ -845,6 +909,14 @@ win32_add_one_solib (const char *name, CORE_ADDR load_addr)
 #endif
     }
 
+#ifndef _WIN32_WCE
+  if (strcasecmp (buf, "ntdll.dll") == 0)
+    {
+      GetSystemDirectoryA (buf, sizeof (buf));
+      strcat (buf, "\\ntdll.dll");
+    }
+#endif
+
 #ifdef __CYGWIN__
   cygwin_conv_to_posix_path (buf, buf2);
 #else
@@ -1295,6 +1367,8 @@ auto_delete_breakpoint (CORE_ADDR stop_pc)
 static int
 get_child_debug_event (struct target_waitstatus *ourstatus)
 {
+  ptid_t ptid;
+
   last_sig = TARGET_SIGNAL_0;
   ourstatus->kind = TARGET_WAITKIND_SPURIOUS;
 
@@ -1344,15 +1418,26 @@ get_child_debug_event (struct target_waitstatus *ourstatus)
         interruption, but high enough so gdbserver doesn't become a
         bottleneck.  */
       if (!WaitForDebugEvent (&current_event, 250))
-       return 0;
+        {
+         DWORD e  = GetLastError();
+
+         if (e == ERROR_PIPE_NOT_CONNECTED)
+           {
+             /* This will happen if the loader fails to succesfully
+                load the application, e.g., if the main executable
+                tries to pull in a non-existing export from a
+                DLL.  */
+             ourstatus->kind = TARGET_WAITKIND_EXITED;
+             ourstatus->value.integer = 1;
+             return 1;
+           }
+
+         return 0;
+        }
     }
 
  gotevent:
 
-  current_inferior =
-    (struct thread_info *) find_inferior_id (&all_threads,
-                                            current_event.dwThreadId);
-
   switch (current_event.dwDebugEventCode)
     {
     case CREATE_THREAD_DEBUG_EVENT:
@@ -1362,8 +1447,9 @@ get_child_debug_event (struct target_waitstatus *ourstatus)
                (unsigned) current_event.dwThreadId));
 
       /* Record the existence of this thread.  */
-      child_add_thread (current_event.dwThreadId,
-                            current_event.u.CreateThread.hThread);
+      child_add_thread (current_event.dwProcessId,
+                       current_event.dwThreadId,
+                       current_event.u.CreateThread.hThread);
       break;
 
     case EXIT_THREAD_DEBUG_EVENT:
@@ -1371,8 +1457,11 @@ get_child_debug_event (struct target_waitstatus *ourstatus)
                "for pid=%d tid=%x\n",
                (unsigned) current_event.dwProcessId,
                (unsigned) current_event.dwThreadId));
-      child_delete_thread (current_event.dwThreadId);
-      break;
+      child_delete_thread (current_event.dwProcessId,
+                          current_event.dwThreadId);
+
+      current_inferior = (struct thread_info *) all_threads.head;
+      return 1;
 
     case CREATE_PROCESS_DEBUG_EVENT:
       OUTMSG2 (("gdbserver: kernel event CREATE_PROCESS_DEBUG_EVENT "
@@ -1388,10 +1477,11 @@ get_child_debug_event (struct target_waitstatus *ourstatus)
       ourstatus->value.execd_pathname = "Main executable";
 
       /* Add the main thread.  */
-      child_add_thread (main_thread_id,
+      child_add_thread (current_event.dwProcessId,
+                       main_thread_id,
                        current_event.u.CreateProcessInfo.hThread);
 
-      ourstatus->value.related_pid = current_event.dwThreadId;
+      ourstatus->value.related_pid = debug_event_ptid (&current_event);
 #ifdef _WIN32_WCE
       if (!attaching)
        {
@@ -1466,18 +1556,21 @@ get_child_debug_event (struct target_waitstatus *ourstatus)
       break;
     }
 
+  ptid = debug_event_ptid (&current_event);
   current_inferior =
-    (struct thread_info *) find_inferior_id (&all_threads,
-                                            current_event.dwThreadId);
+    (struct thread_info *) find_inferior_id (&all_threads, 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. */
-static unsigned long
-win32_wait (struct target_waitstatus *ourstatus, int options)
+static ptid_t
+win32_wait (ptid_t ptid, struct target_waitstatus *ourstatus, int options)
 {
+  struct process_info *process;
+  struct regcache *regcache;
+
   while (1)
     {
       if (!get_child_debug_event (ourstatus))
@@ -1489,14 +1582,17 @@ win32_wait (struct target_waitstatus *ourstatus, int options)
          OUTMSG2 (("Child exited with retcode = %x\n",
                    ourstatus->value.integer));
 
+         process = find_process_pid (current_process_id);
+         remove_process (process);
          win32_clear_inferiors ();
-         return current_event.dwProcessId;
+         return pid_to_ptid (current_event.dwProcessId);
        case TARGET_WAITKIND_STOPPED:
        case TARGET_WAITKIND_LOADED:
          OUTMSG2 (("Child Stopped with signal = %d \n",
-                   our_status.value.sig));
+                   ourstatus->value.sig));
 
-         child_fetch_inferior_registers (-1);
+         regcache = get_thread_regcache (current_inferior, 1);
+         child_fetch_inferior_registers (regcache, -1);
 
          if (ourstatus->kind == TARGET_WAITKIND_LOADED
              && !server_waiting)
@@ -1512,7 +1608,7 @@ win32_wait (struct target_waitstatus *ourstatus, int options)
          if (ourstatus->kind == TARGET_WAITKIND_LOADED)
            ourstatus->kind = TARGET_WAITKIND_STOPPED;
 
-         return current_event.dwThreadId;
+         return debug_event_ptid (&current_event);
        default:
          OUTMSG (("Ignoring unknown internal event, %d\n", ourstatus->kind));
          /* fall-through */
@@ -1528,17 +1624,17 @@ win32_wait (struct target_waitstatus *ourstatus, int options)
 /* Fetch registers from the inferior process.
    If REGNO is -1, fetch all registers; otherwise, fetch at least REGNO.  */
 static void
-win32_fetch_inferior_registers (int regno)
+win32_fetch_inferior_registers (struct regcache *regcache, int regno)
 {
-  child_fetch_inferior_registers (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.  */
 static void
-win32_store_inferior_registers (int regno)
+win32_store_inferior_registers (struct regcache *regcache, int regno)
 {
-  child_store_inferior_registers (regno);
+  child_store_inferior_registers (regcache, regno);
 }
 
 /* Read memory from the inferior process.  This should generally be
@@ -1670,10 +1766,10 @@ static struct target_ops win32_target_ops = {
   NULL,
   win32_request_interrupt,
   NULL,
-  NULL,
-  NULL,
-  NULL,
-  NULL,
+  win32_insert_point,
+  win32_remove_point,
+  win32_stopped_by_watchpoint,
+  win32_stopped_data_address,
   NULL,
   NULL,
   NULL,