Approved by kev@cygnus.com
[deliverable/binutils-gdb.git] / gdb / windows-nat.c
index 67d1728ba8905095fc5d58a50c338845fef59aea..ab5f3f32878dfafd92890e55ab75d83efce49df9 100644 (file)
@@ -1,6 +1,6 @@
 /* Target-vector operations for controlling win32 child processes, for GDB.
-   Copyright 1995, 1996, 1997, 1998, 1999, 2000, 2001 Free Software
-   Foundation, Inc.
+   Copyright 1995, 1996, 1997, 1998, 1999, 2000, 2001
+   Free Software Foundation, Inc.
    Contributed by Cygnus Solutions, A Red Hat Company.
 
    This file is part of GDB.
@@ -79,7 +79,7 @@ enum
 extern struct target_ops child_ops;
 
 static void child_stop (void);
-static int win32_child_thread_alive (int);
+static int win32_child_thread_alive (ptid_t);
 void child_kill_inferior (void);
 
 static int last_sig = 0;       /* Set if a signal was received from the
@@ -233,7 +233,7 @@ child_add_thread (DWORD id, HANDLE h)
   th->h = h;
   th->next = thread_head.next;
   thread_head.next = th;
-  add_thread (id);
+  add_thread (pid_to_ptid (id));
   return th;
 }
 
@@ -262,8 +262,8 @@ child_delete_thread (DWORD id)
   thread_info *th;
 
   if (info_verbose)
-    printf_unfiltered ("[Deleting %s]\n", target_pid_to_str (id));
-  delete_thread (id);
+    printf_unfiltered ("[Deleting %s]\n", target_pid_to_str (pid_to_ptid (id)));
+  delete_thread (pid_to_ptid (id));
 
   for (th = &thread_head;
        th->next != NULL && th->next->id != id;
@@ -313,7 +313,7 @@ do_child_fetch_inferior_registers (int r)
 static void
 child_fetch_inferior_registers (int r)
 {
-  current_thread = thread_rec (inferior_pid, TRUE);
+  current_thread = thread_rec (PIDGET (inferior_ptid), TRUE);
   do_child_fetch_inferior_registers (r);
 }
 
@@ -333,7 +333,7 @@ do_child_store_inferior_registers (int r)
 static void
 child_store_inferior_registers (int r)
 {
-  current_thread = thread_rec (inferior_pid, TRUE);
+  current_thread = thread_rec (PIDGET (inferior_ptid), TRUE);
   do_child_store_inferior_registers (r);
 }
 
@@ -435,12 +435,26 @@ struct safe_symbol_file_add_args
   struct objfile *ret;
 };
 
+/* Maintain a linked list of "so" information. */
+struct so_stuff
+{
+  struct so_stuff *next, **last;
+  DWORD load_addr;
+  int loaded;
+  char name[1];
+} solib_start, *solib_end;
+
 /* Call symbol_file_add with stderr redirected.  We don't care if there
    are errors. */
 static int
 safe_symbol_file_add_stub (void *argv)
 {
 #define p ((struct safe_symbol_file_add_args *)argv)
+  struct so_stuff *so = &solib_start;
+
+  while ((so = so->next))
+    if (so->loaded && strcasecmp (so->name, p->name) == 0)
+      return 0;
   p->ret = symbol_file_add (p->name, p->from_tty, p->addrs, p->mainline, p->flags);
   return !!p->ret;
 #undef p
@@ -453,9 +467,9 @@ safe_symbol_file_add_cleanup (void *p)
 #define sp ((struct safe_symbol_file_add_args *)p)
   gdb_flush (gdb_stderr);
   gdb_flush (gdb_stdout);
-  ui_file_delete (gdb_stderr);
+  /* ui_file_delete (gdb_stderr); */
   ui_file_delete (gdb_stdout);
-  gdb_stderr = sp->err;
+  /* gdb_stderr = sp->err; */
   gdb_stdout = sp->out;
 #undef sp
 }
@@ -475,7 +489,7 @@ safe_symbol_file_add (char *name, int from_tty,
   p.out = gdb_stdout;
   gdb_flush (gdb_stderr);
   gdb_flush (gdb_stdout);
-  gdb_stderr = ui_file_new ();
+  /* gdb_stderr = ui_file_new (); */
   gdb_stdout = ui_file_new ();
   p.name = name;
   p.from_tty = from_tty;
@@ -488,15 +502,6 @@ safe_symbol_file_add (char *name, int from_tty,
   return p.ret;
 }
 
-/* Maintain a linked list of "so" information. */
-struct so_stuff
-{
-  struct so_stuff *next, **last;
-  DWORD load_addr;
-  char name[0];
-}
-solib_start, *solib_end;
-
 /* Remember the maximum DLL length for printing in info dll command. */
 int max_dll_name_len;
 
@@ -504,13 +509,38 @@ static void
 register_loaded_dll (const char *name, DWORD load_addr)
 {
   struct so_stuff *so;
-  so = (struct so_stuff *) xmalloc (sizeof (struct so_stuff) + strlen (name) + 8 + 2);
+  char ppath[MAX_PATH + 1];
+  char buf[MAX_PATH + 1];
+  char cwd[MAX_PATH + 1];
+  char *p;
+  WIN32_FIND_DATA w32_fd;
+  HANDLE h = FindFirstFile(name, &w32_fd);
+  size_t len;
+
+  FindClose (h);
+  strcpy (buf, name);
+  if (GetCurrentDirectory (MAX_PATH + 1, cwd))
+    {
+      p = strrchr (buf, '\\');
+      if (p)
+       p[1] = '\0';
+      SetCurrentDirectory (buf);
+      GetFullPathName (w32_fd.cFileName, MAX_PATH, buf, &p);
+      SetCurrentDirectory (cwd);
+    }
+
+  cygwin_conv_to_posix_path (buf, ppath);
+  so = (struct so_stuff *) xmalloc (sizeof (struct so_stuff) + strlen (ppath) + 8 + 1);
+  so->loaded = 0;
   so->load_addr = load_addr;
-  strcpy (so->name, name);
+  strcpy (so->name, ppath);
 
   solib_end->next = so;
   solib_end = so;
   so->next = NULL;
+  len = strlen (ppath);
+  if (len > max_dll_name_len)
+    max_dll_name_len = len;
 }
 
 /* Wait for child to do something.  Return pid of child, or -1 in case
@@ -523,7 +553,6 @@ handle_load_dll (void *dummy ATTRIBUTE_UNUSED)
   DWORD done;
   char dll_buf[MAX_PATH + 1];
   char *dll_name = NULL;
-  int len;
   char *p;
 
   dll_buf[0] = dll_buf[sizeof (dll_buf) - 1] = '\0';
@@ -592,15 +621,7 @@ handle_load_dll (void *dummy ATTRIBUTE_UNUSED)
   if (!dll_name)
     return 1;
 
-  (void) strlwr (dll_name);
-
-  while ((p = strchr (dll_name, '\\')))
-    *p = '/';
-
   register_loaded_dll (dll_name, (DWORD) event->lpBaseOfDll + 0x1000);
-  len = strlen (dll_name);
-  if (len > max_dll_name_len)
-    max_dll_name_len = len;
 
   return 1;
 }
@@ -630,8 +651,8 @@ child_clear_solibs (void)
 }
 
 /* Add DLL symbol information. */
-void
-solib_symbols_add (char *name, CORE_ADDR load_addr)
+static void
+solib_symbols_add (char *name, int from_tty, CORE_ADDR load_addr)
 {
   struct section_addr_info section_addrs;
 
@@ -645,14 +666,14 @@ solib_symbols_add (char *name, CORE_ADDR load_addr)
   memset (&section_addrs, 0, sizeof (section_addrs));
   section_addrs.other[0].name = ".text";
   section_addrs.other[0].addr = load_addr;
-  safe_symbol_file_add (name, 0, &section_addrs, 0, OBJF_SHARED);
+  safe_symbol_file_add (name, from_tty, NULL, 0, OBJF_SHARED);
 
   return;
 }
 
 /* Load DLL symbol info. */
 void
-dll_symbol_command (char *args, int from_tty ATTRIBUTE_UNUSED)
+dll_symbol_command (char *args, int from_tty)
 {
   int n;
   dont_repeat ();
@@ -669,7 +690,7 @@ dll_symbol_command (char *args, int from_tty ATTRIBUTE_UNUSED)
       args = newargs;
     }
 
-  safe_symbol_file_add (args, 0, NULL, 0, OBJF_SHARED | OBJF_USERLOADED);
+  safe_symbol_file_add (args, from_tty, NULL, 0, OBJF_SHARED | OBJF_USERLOADED);
 }
 
 /* List currently loaded DLLs. */
@@ -777,6 +798,8 @@ handle_exception (struct target_waitstatus *ourstatus)
       last_sig = SIGILL;
       break;
     default:
+      if (current_event.u.Exception.dwFirstChance)
+       return 0;
       printf_unfiltered ("gdb: unknown target exception 0x%08lx at 0x%08lx\n",
                    current_event.u.Exception.ExceptionRecord.ExceptionCode,
        (DWORD) current_event.u.Exception.ExceptionRecord.ExceptionAddress);
@@ -849,7 +872,8 @@ get_child_debug_event (int pid ATTRIBUTE_UNUSED, struct target_waitstatus *ourst
                             current_event.u.CreateThread.hThread);
       if (info_verbose)
        printf_unfiltered ("[New %s]\n",
-                          target_pid_to_str (current_event.dwThreadId));
+                          target_pid_to_str (
+                            pid_to_ptid (current_event.dwThreadId)));
       retval = current_event.dwThreadId;
       break;
 
@@ -867,6 +891,7 @@ get_child_debug_event (int pid ATTRIBUTE_UNUSED, struct target_waitstatus *ourst
                     (unsigned) current_event.dwProcessId,
                     (unsigned) current_event.dwThreadId,
                     "CREATE_PROCESS_DEBUG_EVENT"));
+      CloseHandle (current_event.u.CreateProcessInfo.hFile);
       current_process_handle = current_event.u.CreateProcessInfo.hProcess;
 
       main_thread_id = current_event.dwThreadId;
@@ -896,6 +921,7 @@ get_child_debug_event (int pid ATTRIBUTE_UNUSED, struct target_waitstatus *ourst
                     (unsigned) current_event.dwProcessId,
                     (unsigned) current_event.dwThreadId,
                     "LOAD_DLL_DEBUG_EVENT"));
+      CloseHandle (current_event.u.LoadDll.hFile);
       catch_errors (handle_load_dll, NULL, (char *) "", RETURN_MASK_ALL);
       registers_changed ();    /* mark all regs invalid */
       ourstatus->kind = TARGET_WAITKIND_LOADED;
@@ -915,8 +941,8 @@ get_child_debug_event (int pid ATTRIBUTE_UNUSED, struct target_waitstatus *ourst
                     (unsigned) current_event.dwProcessId,
                     (unsigned) current_event.dwThreadId,
                     "EXCEPTION_DEBUG_EVENT"));
-      handle_exception (ourstatus);
-      retval = current_event.dwThreadId;
+      if (handle_exception (ourstatus))
+       retval = current_event.dwThreadId;
       break;
 
     case OUTPUT_DEBUG_STRING_EVENT:    /* message from the kernel */
@@ -942,7 +968,7 @@ get_child_debug_event (int pid ATTRIBUTE_UNUSED, struct target_waitstatus *ourst
   else
     {
       current_thread = th ? : thread_rec (current_event.dwThreadId, TRUE);
-      inferior_pid = retval;
+      inferior_ptid = pid_to_ptid (retval);
     }
 
 out:
@@ -950,9 +976,11 @@ out:
 }
 
 /* Wait for interesting events to occur in the target process. */
-static int
-child_wait (int pid, struct target_waitstatus *ourstatus)
+static ptid_t
+child_wait (ptid_t ptid, struct target_waitstatus *ourstatus)
 {
+  int pid = PIDGET (ptid);
+
   /* We loop when we get a non-standard exception rather than return
      with a SPURIOUS because resume can try and step or modify things,
      which needs a current_thread->h.  But some of these exceptions mark
@@ -963,7 +991,7 @@ child_wait (int pid, struct target_waitstatus *ourstatus)
     {
       int retval = get_child_debug_event (pid, ourstatus);
       if (retval)
-       return retval;
+       return pid_to_ptid (retval);
       else
        {
          int detach = 0;
@@ -1009,32 +1037,67 @@ do_initial_child_stuff (DWORD pid)
   return;
 }
 
-/* Attach to process PID, then initialize for debugging it.  */
+/* Since Windows XP, detaching from a process is supported by Windows.
+   The following code tries loading the appropriate functions dynamically.
+   If loading these functions succeeds use them to actually detach from
+   the inferior process, otherwise behave as usual, pretending that
+   detach has worked. */
+static BOOL WINAPI (*DebugSetProcessKillOnExit)(BOOL);
+static BOOL WINAPI (*DebugActiveProcessStop)(DWORD);
 
+static int
+has_detach_ability ()
+{
+  static HMODULE kernel32 = NULL;
+
+  if (!kernel32)
+    kernel32 = LoadLibrary ("kernel32.dll");
+  if (kernel32)
+    {
+      if (!DebugSetProcessKillOnExit)
+       DebugSetProcessKillOnExit = GetProcAddress (kernel32,
+                                                "DebugSetProcessKillOnExit");
+      if (!DebugActiveProcessStop)
+       DebugActiveProcessStop = GetProcAddress (kernel32,
+                                                "DebugActiveProcessStop");
+      if (DebugSetProcessKillOnExit && DebugActiveProcessStop)
+       return 1;
+    }
+  return 0;
+}
+
+/* Attach to process PID, then initialize for debugging it.  */
 static void
 child_attach (char *args, int from_tty)
 {
   BOOL ok;
-  DWORD pid = strtoul (args, 0, 0);
+  DWORD pid;
 
   if (!args)
     error_no_arg ("process-id to attach");
 
+  pid = strtoul (args, 0, 0);
   ok = DebugActiveProcess (pid);
 
   if (!ok)
     error ("Can't attach to process.");
 
+  if (has_detach_ability ())
+    {
+      attach_flag = 1;
+      DebugSetProcessKillOnExit (FALSE);
+    }
+
   if (from_tty)
     {
       char *exec_file = (char *) get_exec_file (0);
 
       if (exec_file)
        printf_unfiltered ("Attaching to program `%s', %s\n", exec_file,
-                          target_pid_to_str (pid));
+                          target_pid_to_str (pid_to_ptid (pid)));
       else
        printf_unfiltered ("Attaching to %s\n",
-                          target_pid_to_str (pid));
+                          target_pid_to_str (pid_to_ptid (pid)));
 
       gdb_flush (gdb_stdout);
     }
@@ -1046,16 +1109,30 @@ child_attach (char *args, int from_tty)
 static void
 child_detach (char *args ATTRIBUTE_UNUSED, int from_tty)
 {
-  if (from_tty)
+  int detached = 1;
+
+  if (has_detach_ability ())
+    {
+      delete_command (NULL, 0);
+      child_continue (DBG_CONTINUE, -1);
+      if (!DebugActiveProcessStop (current_event.dwProcessId))
+        {
+         error ("Can't detach process %lu (error %lu)",
+                current_event.dwProcessId, GetLastError ());
+         detached = 0;
+        }
+      DebugSetProcessKillOnExit (FALSE);
+    }
+  if (detached && from_tty)
     {
       char *exec_file = get_exec_file (0);
       if (exec_file == 0)
        exec_file = "";
-      printf_unfiltered ("Detaching from program: %s %s\n", exec_file,
-                        target_pid_to_str (inferior_pid));
+      printf_unfiltered ("Detaching from program: %s, Pid %lu\n", exec_file,
+                        current_event.dwProcessId);
       gdb_flush (gdb_stdout);
     }
-  inferior_pid = 0;
+  inferior_ptid = null_ptid;
   unpush_target (&child_ops);
 }
 
@@ -1065,7 +1142,7 @@ static void
 child_files_info (struct target_ops *ignore ATTRIBUTE_UNUSED)
 {
   printf_unfiltered ("\tUsing the running image of %s %s.\n",
-      attach_flag ? "attached" : "child", target_pid_to_str (inferior_pid));
+      attach_flag ? "attached" : "child", target_pid_to_str (inferior_ptid));
 }
 
 /* ARGSUSED */
@@ -1075,7 +1152,7 @@ child_open (char *arg ATTRIBUTE_UNUSED, int from_tty ATTRIBUTE_UNUSED)
   error ("Use the \"run\" command to start a Unix child process.");
 }
 
-/* Start an inferior win32 child process and sets inferior_pid to its pid.
+/* Start an inferior win32 child process and sets inferior_ptid to its pid.
    EXEC_FILE is the file to run.
    ALLARGS is a string containing the arguments to the program.
    ENV is the environment vector to pass.  Errors reported with error().  */
@@ -1203,6 +1280,8 @@ child_create_inferior (char *exec_file, char *allargs, char **env)
   if (!ret)
     error ("Error creating process %s, (error %d)\n", exec_file, GetLastError ());
 
+  CloseHandle (pi.hThread);
+  CloseHandle (pi.hProcess);
   do_initial_child_stuff (pi.dwProcessId);
 
   /* child_continue (DBG_CONTINUE, -1); */
@@ -1275,11 +1354,12 @@ child_kill_inferior (void)
 }
 
 void
-child_resume (int pid, int step, enum target_signal sig)
+child_resume (ptid_t ptid, int step, enum target_signal sig)
 {
   thread_info *th;
   DWORD continue_status = last_sig > 0 && last_sig < NSIG ?
   DBG_EXCEPTION_NOT_HANDLED : DBG_CONTINUE;
+  int pid = PIDGET (ptid);
 
   last_sig = 0;
 
@@ -1325,7 +1405,8 @@ child_can_run (void)
 static void
 child_close (int x ATTRIBUTE_UNUSED)
 {
-  DEBUG_EVENTS (("gdb: child_close, inferior_pid=%d\n", inferior_pid));
+  DEBUG_EVENTS (("gdb: child_close, inferior_ptid=%d\n",
+                PIDGET (inferior_ptid)));
 }
 
 struct target_ops child_ops;
@@ -1387,7 +1468,6 @@ _initialize_inftarg (void)
               "Load dll library symbols from FILE.");
   c->completer = filename_completer;
 
-  auto_solib_add = 1;
   add_com_alias ("sharedlibrary", "dll-symbols", class_alias, 1);
 
   add_show_from_set (add_set_cmd ("new-console", class_support, var_boolean,
@@ -1436,17 +1516,21 @@ _initialize_inftarg (void)
    by "polling" it.  If WaitForSingleObject returns WAIT_OBJECT_0
    it means that the pid has died.  Otherwise it is assumed to be alive. */
 static int
-win32_child_thread_alive (int pid)
+win32_child_thread_alive (ptid_t ptid)
 {
+  int pid = PIDGET (ptid);
+
   return WaitForSingleObject (thread_rec (pid, FALSE)->h, 0) == WAIT_OBJECT_0 ?
     FALSE : TRUE;
 }
 
 /* Convert pid to printable format. */
 char *
-cygwin_pid_to_str (int pid)
+cygwin_pid_to_str (ptid_t ptid)
 {
   static char buf[80];
+  int pid = PIDGET (ptid);
+
   if ((DWORD) pid == current_event.dwProcessId)
     sprintf (buf, "process %d", pid);
   else
@@ -1480,7 +1564,7 @@ core_dll_symbols_add (char *dll_name, DWORD base_addr)
   }
 
   register_loaded_dll (dll_name, base_addr + 0x1000);
-  solib_symbols_add (dll_name, (CORE_ADDR) base_addr + 0x1000);
+  solib_symbols_add (dll_name, 0, (CORE_ADDR) base_addr + 0x1000);
 
 out:
   return 1;
@@ -1623,8 +1707,10 @@ out:
 }
 
 void
-child_solib_add (char *filename ATTRIBUTE_UNUSED, int from_tty ATTRIBUTE_UNUSED, struct target_ops *target)
+child_solib_add (char *filename ATTRIBUTE_UNUSED, int from_tty, struct target_ops *target, int readsyms)
 {
+  if (!readsyms)
+    return;
   if (core_bfd)
     {
       child_clear_solibs ();
@@ -1633,7 +1719,7 @@ child_solib_add (char *filename ATTRIBUTE_UNUSED, int from_tty ATTRIBUTE_UNUSED,
   else
     {
       if (solib_end && solib_end->name)
-       solib_symbols_add (solib_end->name, solib_end->load_addr);
+       solib_symbols_add (solib_end->name, from_tty, solib_end->load_addr);
     }
 }
 
This page took 0.031979 seconds and 4 git commands to generate.