* elf-bfd.h (struct elf_backend_data): Add
[deliverable/binutils-gdb.git] / gdb / windows-nat.c
index 897a541ba9d36ea840cd6e8c52101e4c8f62a02f..601f28bf1294b0e140574aa5ca516c5fa621a4ca 100644 (file)
@@ -1,7 +1,7 @@
 /* Target-vector operations for controlling win32 child processes, for GDB.
 
-   Copyright 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003 Free
-   Software Foundation, Inc.
+   Copyright 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004
+   Free Software Foundation, Inc.
 
    Contributed by Cygnus Solutions, A Red Hat Company.
 
@@ -27,7 +27,6 @@
 /* We assume we're being built with and will be used for cygwin.  */
 
 #include "defs.h"
-#include "tm.h"                        /* required for SSE registers */
 #include "frame.h"             /* required by inferior.h */
 #include "inferior.h"
 #include "target.h"
@@ -36,7 +35,6 @@
 #include "completer.h"
 #include "regcache.h"
 #include "top.h"
-#include "i386-tdep.h"
 #include <signal.h>
 #include <sys/types.h>
 #include <fcntl.h>
 #include "gdbcmd.h"
 #include <sys/param.h>
 #include <unistd.h>
+#include "exec.h"
 
-/* The ui's event loop. */
-extern int (*ui_loop_hook) (int signo);
+#include "i386-tdep.h"
+#include "i387-tdep.h"
 
 /* If we're not using the old Cygwin header file set, define the
    following which never should have been in the generic Win32 API
@@ -70,16 +69,12 @@ enum
 #include <sys/procfs.h>
 #include <psapi.h>
 
-#ifdef HAVE_SSE_REGS
 #define CONTEXT_DEBUGGER_DR CONTEXT_DEBUGGER | CONTEXT_DEBUG_REGISTERS \
        | CONTEXT_EXTENDED_REGISTERS
-#else
-#define CONTEXT_DEBUGGER_DR CONTEXT_DEBUGGER | CONTEXT_DEBUG_REGISTERS
-#endif
 
 static unsigned dr[8];
-static int debug_registers_changed = 0;
-static int debug_registers_used = 0;
+static int debug_registers_changed;
+static int debug_registers_used;
 
 /* The string sent by cygwin when it processes a signal.
    FIXME: This should be in a cygwin include file. */
@@ -110,6 +105,7 @@ typedef struct thread_info_struct
     HANDLE h;
     char *name;
     int suspend_count;
+    int reload_context;
     CONTEXT context;
     STACKFRAME sf;
   }
@@ -187,7 +183,6 @@ static const int mappings[] =
   context_offset (FloatSave.DataSelector),
   context_offset (FloatSave.DataOffset),
   context_offset (FloatSave.ErrorSelector)
-#ifdef HAVE_SSE_REGS
   /* XMM0-7 */ ,
   context_offset (ExtendedRegisters[10*16]),
   context_offset (ExtendedRegisters[11*16]),
@@ -199,7 +194,6 @@ static const int mappings[] =
   context_offset (ExtendedRegisters[17*16]),
   /* MXCSR */
   context_offset (ExtendedRegisters[24])
-#endif
 };
 
 #undef context_offset
@@ -232,7 +226,6 @@ check (BOOL ok, const char *file, int line)
                     GetLastError ());
 }
 
-
 /* Find a thread record given a thread id.
    If get_context then also retrieve the context for this
    thread. */
@@ -250,19 +243,7 @@ thread_rec (DWORD id, int get_context)
              th->suspend_count = SuspendThread (th->h) + 1;
            else if (get_context < 0)
              th->suspend_count = -1;
-
-           th->context.ContextFlags = CONTEXT_DEBUGGER_DR;
-           GetThreadContext (th->h, &th->context);
-           if (id == current_event.dwThreadId)
-             {
-               /* Copy dr values from that thread.  */
-               dr[0] = th->context.Dr0;
-               dr[1] = th->context.Dr1;
-               dr[2] = th->context.Dr2;
-               dr[3] = th->context.Dr3;
-               dr[6] = th->context.Dr6;
-               dr[7] = th->context.Dr7;
-             }
+           th->reload_context = 1;
          }
        return th;
       }
@@ -352,37 +333,67 @@ do_child_fetch_inferior_registers (int r)
 {
   char *context_offset = ((char *) &current_thread->context) + mappings[r];
   long l;
-  if (r == FCS_REGNUM)
+
+  if (!current_thread)
+    return;    /* Windows sometimes uses a non-existent thread id in its
+                  events */
+
+  if (current_thread->reload_context)
+    {
+      thread_info *th = current_thread;
+      th->context.ContextFlags = CONTEXT_DEBUGGER_DR;
+      GetThreadContext (th->h, &th->context);
+      /* Copy dr values from that thread.  */
+      dr[0] = th->context.Dr0;
+      dr[1] = th->context.Dr1;
+      dr[2] = th->context.Dr2;
+      dr[3] = th->context.Dr3;
+      dr[6] = th->context.Dr6;
+      dr[7] = th->context.Dr7;
+      current_thread->reload_context = 0;
+    }
+
+#define I387_ST0_REGNUM I386_ST0_REGNUM
+
+  if (r == I387_FISEG_REGNUM)
     {
       l = *((long *) context_offset) & 0xffff;
-      supply_register (r, (char *) &l);
+      regcache_raw_supply (current_regcache, r, (char *) &l);
     }
-  else if (r == FOP_REGNUM)
+  else if (r == I387_FOP_REGNUM)
     {
       l = (*((long *) context_offset) >> 16) & ((1 << 11) - 1);
-      supply_register (r, (char *) &l);
+      regcache_raw_supply (current_regcache, r, (char *) &l);
     }
   else if (r >= 0)
-    supply_register (r, context_offset);
+    regcache_raw_supply (current_regcache, r, context_offset);
   else
     {
       for (r = 0; r < NUM_REGS; r++)
        do_child_fetch_inferior_registers (r);
     }
+
+#undef I387_ST0_REGNUM
 }
 
 static void
 child_fetch_inferior_registers (int r)
 {
   current_thread = thread_rec (PIDGET (inferior_ptid), TRUE);
-  do_child_fetch_inferior_registers (r);
+  /* Check if current_thread exists.  Windows sometimes uses a non-existent
+     thread id in its events */
+  if (current_thread)
+    do_child_fetch_inferior_registers (r);
 }
 
 static void
 do_child_store_inferior_registers (int r)
 {
-  if (r >= 0)
-    regcache_collect (r, ((char *) &current_thread->context) + mappings[r]);
+  if (!current_thread)
+    /* Windows sometimes uses a non-existent thread id in its events */;
+  else if (r >= 0)
+    regcache_raw_collect (current_regcache, r,
+                         ((char *) &current_thread->context) + mappings[r]);
   else
     {
       for (r = 0; r < NUM_REGS; r++)
@@ -395,7 +406,10 @@ static void
 child_store_inferior_registers (int r)
 {
   current_thread = thread_rec (PIDGET (inferior_ptid), TRUE);
-  do_child_store_inferior_registers (r);
+  /* Check if current_thread exists.  Windows sometimes uses a non-existent
+     thread id in its events */
+  if (current_thread)
+    do_child_store_inferior_registers (r);
 }
 
 static int psapi_loaded = 0;
@@ -1178,7 +1192,7 @@ child_continue (DWORD continue_status, int id)
          th->suspend_count = 0;
          if (debug_registers_changed)
            {
-             /* Only change the value of the debug reisters */
+             /* Only change the value of the debug registers */
              th->context.ContextFlags = CONTEXT_DEBUG_REGISTERS;
              th->context.Dr0 = dr[0];
              th->context.Dr1 = dr[1];
@@ -1196,6 +1210,19 @@ child_continue (DWORD continue_status, int id)
   return res;
 }
 
+/* Called in pathological case where Windows fails to send a
+   CREATE_PROCESS_DEBUG_EVENT after an attach.  */
+DWORD
+fake_create_process (void)
+{
+  current_process_handle = OpenProcess (PROCESS_ALL_ACCESS, FALSE,
+                                       current_event.dwProcessId);
+  main_thread_id = current_event.dwThreadId;
+  current_thread = child_add_thread (main_thread_id,
+                                    current_event.u.CreateThread.hThread);
+  return main_thread_id;
+}
+
 /* Get the next event from the child.  Return 1 if the event requires
    handling by WFI (or whatever).
  */
@@ -1204,7 +1231,7 @@ get_child_debug_event (int pid, struct target_waitstatus *ourstatus)
 {
   BOOL debug_event;
   DWORD continue_status, event_code;
-  thread_info *th = NULL;
+  thread_info *th;
   static thread_info dummy_thread_info;
   int retval = 0;
 
@@ -1218,6 +1245,7 @@ get_child_debug_event (int pid, struct target_waitstatus *ourstatus)
 
   event_code = current_event.dwDebugEventCode;
   ourstatus->kind = TARGET_WAITKIND_SPURIOUS;
+  th = NULL;
 
   switch (event_code)
     {
@@ -1227,7 +1255,17 @@ get_child_debug_event (int pid, struct target_waitstatus *ourstatus)
                     (unsigned) current_event.dwThreadId,
                     "CREATE_THREAD_DEBUG_EVENT"));
       if (saw_create != 1)
-       break;
+       {
+         if (!saw_create && attach_flag)
+           {
+             /* Kludge around a Windows bug where first event is a create
+                thread event.  Caused when attached process does not have
+                a main thread. */
+             retval = ourstatus->value.related_pid = fake_create_process ();
+             saw_create++;
+           }
+         break;
+       }
       /* Record the existence of this thread */
       th = child_add_thread (current_event.dwThreadId,
                             current_event.u.CreateThread.hThread);
@@ -1243,10 +1281,11 @@ get_child_debug_event (int pid, struct target_waitstatus *ourstatus)
                     (unsigned) current_event.dwProcessId,
                     (unsigned) current_event.dwThreadId,
                     "EXIT_THREAD_DEBUG_EVENT"));
-      if (saw_create != 1)
-       break;
-      child_delete_thread (current_event.dwThreadId);
-      th = &dummy_thread_info;
+      if (current_event.dwThreadId != main_thread_id)
+       {
+         child_delete_thread (current_event.dwThreadId);
+         th = &dummy_thread_info;
+       }
       break;
 
     case CREATE_PROCESS_DEBUG_EVENT:
@@ -1262,12 +1301,10 @@ get_child_debug_event (int pid, struct target_waitstatus *ourstatus)
        }
 
       current_process_handle = current_event.u.CreateProcessInfo.hProcess;
+      if (main_thread_id)
+       child_delete_thread (main_thread_id);
       main_thread_id = current_event.dwThreadId;
       /* Add the main thread */
-#if 0
-      th = child_add_thread (current_event.dwProcessId,
-                            current_event.u.CreateProcessInfo.hProcess);
-#endif
       th = child_add_thread (main_thread_id,
                             current_event.u.CreateProcessInfo.hThread);
       retval = ourstatus->value.related_pid = current_event.dwThreadId;
@@ -1352,8 +1389,8 @@ get_child_debug_event (int pid, struct target_waitstatus *ourstatus)
     CHECK (child_continue (continue_status, -1));
   else
     {
-      current_thread = th ? : thread_rec (current_event.dwThreadId, TRUE);
       inferior_ptid = pid_to_ptid (retval);
+      current_thread = th ?: thread_rec (current_event.dwThreadId, TRUE);
     }
 
 out:
@@ -1381,8 +1418,8 @@ child_wait (ptid_t ptid, struct target_waitstatus *ourstatus)
        {
          int detach = 0;
 
-         if (ui_loop_hook != NULL)
-           detach = ui_loop_hook (0);
+         if (deprecated_ui_loop_hook != NULL)
+           detach = deprecated_ui_loop_hook (0);
 
          if (detach)
            child_kill_inferior ();
@@ -1568,10 +1605,9 @@ child_attach (char *args, int from_tty)
     }
 
   if (has_detach_ability ())
-    {
-      attach_flag = 1;
-      DebugSetProcessKillOnExit (FALSE);
-    }
+    DebugSetProcessKillOnExit (FALSE);
+
+  attach_flag = 1;
 
   if (from_tty)
     {
@@ -1621,6 +1657,36 @@ child_detach (char *args, int from_tty)
   unpush_target (&child_ops);
 }
 
+char *
+child_pid_to_exec_file (int pid)
+{
+  /* Try to find the process path using the Cygwin internal process list
+     pid isn't a valid pid, unfortunately.  Use current_event.dwProcessId
+     instead.  */
+  /* TODO: Also find native Windows processes using CW_GETPINFO_FULL.  */
+
+  static char path[MAX_PATH + 1];
+  char *path_ptr = NULL;
+  int cpid;
+  struct external_pinfo *pinfo;
+
+  cygwin_internal (CW_LOCK_PINFO, 1000);
+  for (cpid = 0;
+       (pinfo = (struct external_pinfo *)
+                       cygwin_internal (CW_GETPINFO, cpid | CW_NEXTPID));
+       cpid = pinfo->pid)
+    {
+      if (pinfo->dwProcessId == current_event.dwProcessId) /* Got it */
+       {
+         cygwin_conv_to_full_posix_path (pinfo->progname, path);
+         path_ptr = path; 
+         break;
+       }
+    }
+  cygwin_internal (CW_UNLOCK_PINFO);
+  return path_ptr; 
+}
+
 /* Print status information about what we're accessing.  */
 
 static void
@@ -1630,7 +1696,6 @@ child_files_info (struct target_ops *ignore)
       attach_flag ? "attached" : "child", target_pid_to_str (inferior_ptid));
 }
 
-/* ARGSUSED */
 static void
 child_open (char *arg, int from_tty)
 {
@@ -1643,7 +1708,8 @@ child_open (char *arg, int from_tty)
    ENV is the environment vector to pass.  Errors reported with error().  */
 
 static void
-child_create_inferior (char *exec_file, char *allargs, char **env)
+child_create_inferior (char *exec_file, char *allargs, char **env,
+                      int from_tty)
 {
   char *winenv;
   char *temp;
@@ -1694,6 +1760,8 @@ child_create_inferior (char *exec_file, char *allargs, char **env)
   if (new_console)
     flags |= CREATE_NEW_CONSOLE;
 
+  attach_flag = 0;
+
   args = alloca (strlen (toexec) + strlen (allargs) + 2);
   strcpy (args, toexec);
   strcat (args, " ");
@@ -1895,7 +1963,8 @@ child_kill_inferior (void)
   CHECK (CloseHandle (current_process_handle));
 
   /* this may fail in an attached process so don't check. */
-  (void) CloseHandle (current_thread->h);
+  if (current_thread && current_thread->h)
+    (void) CloseHandle (current_thread->h);
   target_mourn_inferior ();    /* or just child_mourn_inferior? */
 }
 
@@ -2040,6 +2109,7 @@ init_child_ops (void)
   child_ops.to_has_registers = 1;
   child_ops.to_has_execution = 1;
   child_ops.to_magic = OPS_MAGIC;
+  child_ops.to_pid_to_exec_file = child_pid_to_exec_file;
 }
 
 void
@@ -2055,47 +2125,54 @@ _initialize_win32_nat (void)
 
   add_com_alias ("sharedlibrary", "dll-symbols", class_alias, 1);
 
-  add_show_from_set (add_set_cmd ("shell", class_support, var_boolean,
-                                 (char *) &useshell,
-                "Set use of shell to start subprocess.",
-                                 &setlist),
-                    &showlist);
-
-  add_show_from_set (add_set_cmd ("new-console", class_support, var_boolean,
-                                 (char *) &new_console,
-                "Set creation of new console when creating child process.",
-                                 &setlist),
-                    &showlist);
-
-  add_show_from_set (add_set_cmd ("new-group", class_support, var_boolean,
-                                 (char *) &new_group,
-                  "Set creation of new group when creating child process.",
-                                 &setlist),
-                    &showlist);
-
-  add_show_from_set (add_set_cmd ("debugexec", class_support, var_boolean,
-                                 (char *) &debug_exec,
-                      "Set whether to display execution in child process.",
-                                 &setlist),
-                    &showlist);
-
-  add_show_from_set (add_set_cmd ("debugevents", class_support, var_boolean,
-                                 (char *) &debug_events,
-                  "Set whether to display kernel events in child process.",
-                                 &setlist),
-                    &showlist);
-
-  add_show_from_set (add_set_cmd ("debugmemory", class_support, var_boolean,
-                                 (char *) &debug_memory,
-                "Set whether to display memory accesses in child process.",
-                                 &setlist),
-                    &showlist);
-
-  add_show_from_set (add_set_cmd ("debugexceptions", class_support, var_boolean,
-                                 (char *) &debug_exceptions,
-              "Set whether to display kernel exceptions in child process.",
-                                 &setlist),
-                    &showlist);
+  deprecated_add_show_from_set
+    (add_set_cmd ("shell", class_support, var_boolean,
+                 (char *) &useshell,
+                 "Set use of shell to start subprocess.",
+                 &setlist),
+     &showlist);
+
+  deprecated_add_show_from_set
+    (add_set_cmd ("new-console", class_support, var_boolean,
+                 (char *) &new_console,
+                 "Set creation of new console when creating child process.",
+                 &setlist),
+     &showlist);
+
+  deprecated_add_show_from_set
+    (add_set_cmd ("new-group", class_support, var_boolean,
+                 (char *) &new_group,
+                 "Set creation of new group when creating child process.",
+                 &setlist),
+     &showlist);
+
+  deprecated_add_show_from_set
+    (add_set_cmd ("debugexec", class_support, var_boolean,
+                 (char *) &debug_exec,
+                 "Set whether to display execution in child process.",
+                 &setlist),
+     &showlist);
+
+  deprecated_add_show_from_set
+    (add_set_cmd ("debugevents", class_support, var_boolean,
+                 (char *) &debug_events,
+                 "Set whether to display kernel events in child process.",
+                 &setlist),
+     &showlist);
+
+  deprecated_add_show_from_set
+    (add_set_cmd ("debugmemory", class_support, var_boolean,
+                 (char *) &debug_memory,
+                 "Set whether to display memory accesses in child process.",
+                 &setlist),
+     &showlist);
+
+  deprecated_add_show_from_set
+    (add_set_cmd ("debugexceptions", class_support, var_boolean,
+                 (char *) &debug_exceptions,
+                 "Set whether to display kernel exceptions in child process.",
+                 &setlist),
+     &showlist);
 
   add_info ("dll", info_dll_command, "Status of loaded DLLs.");
   add_info_alias ("sharedlibrary", "dll", 1);
@@ -2147,7 +2224,6 @@ cygwin_get_dr6 (void)
   return dr[6];
 }
 
-
 /* Determine if the thread referenced by "pid" is alive
    by "polling" it.  If WaitForSingleObject returns WAIT_OBJECT_0
    it means that the pid has died.  Otherwise it is assumed to be alive. */
@@ -2202,7 +2278,7 @@ core_dll_symbols_add (char *dll_name, DWORD base_addr)
   register_loaded_dll (dll_name, base_addr + 0x1000);
   solib_symbols_add (dll_name, 0, (CORE_ADDR) base_addr + 0x1000);
 
-out:
+ out:
   return 1;
 }
 
@@ -2300,20 +2376,20 @@ core_section_load_dll_symbols (bfd * abfd, asection * sect, void *obj)
   if (strncmp (sect->name, ".module", 7))
     return;
 
-  buf = (char *) xmalloc (sect->_raw_size + 1);
+  buf = (char *) xmalloc (bfd_get_section_size (sect) + 1);
   if (!buf)
     {
       printf_unfiltered ("memory allocation failed for %s\n", sect->name);
       goto out;
     }
-  if (!bfd_get_section_contents (abfd, sect, buf, 0, sect->_raw_size))
+  if (!bfd_get_section_contents (abfd, sect, buf, 0, bfd_get_section_size (sect)))
     goto out;
 
   pstatus = (struct win32_pstatus *) buf;
 
   memmove (&base_addr, &(pstatus->data.module_info.base_address), sizeof (base_addr));
   dll_name_size = pstatus->data.module_info.module_name_size;
-  if (offsetof (struct win32_pstatus, data.module_info.module_name) + dll_name_size > sect->_raw_size)
+  if (offsetof (struct win32_pstatus, data.module_info.module_name) + dll_name_size > bfd_get_section_size (sect))
       goto out;
 
   dll_name = (char *) xmalloc (dll_name_size + 1);
@@ -2373,7 +2449,7 @@ fetch_elf_core_registers (char *core_reg_sect,
       return;
     }
   for (r = 0; r < NUM_REGS; r++)
-    supply_register (r, core_reg_sect + mappings[r]);
+    regcache_raw_supply (current_regcache, r, core_reg_sect + mappings[r]);
 }
 
 static struct core_fns win32_elf_core_fns =
@@ -2388,7 +2464,7 @@ static struct core_fns win32_elf_core_fns =
 void
 _initialize_core_win32 (void)
 {
-  add_core_fns (&win32_elf_core_fns);
+  deprecated_add_core_fns (&win32_elf_core_fns);
 }
 
 void
This page took 0.051508 seconds and 4 git commands to generate.