2007-07-17 Pedro Alves <pedro_alves@portugalmail.pt>
authorDaniel Jacobowitz <drow@false.org>
Tue, 17 Jul 2007 12:51:41 +0000 (12:51 +0000)
committerDaniel Jacobowitz <drow@false.org>
Tue, 17 Jul 2007 12:51:41 +0000 (12:51 +0000)
    Daniel Jacobowitz  <dan@codesourcery.com>

* config/i386/cygwin.mt (TDEPFILES): Add solib-target.o.
* coff-pe-read.c (read_pe_exported_syms): Delete verbose
printf.
* NEWS: Mention gdbserver DLL support.

* gdb.base/unload.c (dlopen, dlsym, dlclose, dlerror): Define
for __WIN32__.
(SHLIB_NAME): Delete definition.  Always pass dlerror to fprintf.
* gdb.base/unload.exp: Use shared library test routines.

* inferiors.c (all_dlls, dlls_changed, get_dll): New.
(add_thread): Minor cleanups.
(clear_inferiors): Move lower in the file.  Clear the DLL
list.
(free_one_dll, match_dll, loaded_dll, unloaded_dll, clear_list): New.
* remote-utils.c (prepare_resume_reply): Check dlls_changed.
(xml_escape_text): New.
* server.c (handle_query): Handle qXfer:libraries:read.  Report it
for qSupported.
(handle_v_cont): Report errors.
(gdbserver_version): Update.
(main): Correct size of own_buf.  Do not report initial DLL events.
* server.h (struct dll_info, all_dlls, dlls_changed, loaded_dll)
(unloaded_dll, xml_escape_text): New.
* win32-low.c (enum target_waitkind): Update comments.
(win32_add_one_solib, get_image_name, winapi_EnumProcessModules)
(winapi_GetModuleInformation, winapi_GetModuleFileNameExA)
(win32_EnumProcessModules, win32_GetModuleInformation)
(win32_GetModuleFileNameExA, load_psapi, psapi_get_dll_name)
(winapi_CreateToolhelp32Snapshot, winapi_Module32First)
(winapi_Module32Next, win32_CreateToolhelp32Snapshot)
(win32_Module32First, win32_Module32Next, load_toolhelp)
(toolhelp_get_dll_name, handle_load_dll, handle_unload_dll): New.
(get_child_debug_event): Handle DLL events.
(win32_wait): Likewise.

13 files changed:
gdb/ChangeLog
gdb/NEWS
gdb/coff-pe-read.c
gdb/config/i386/cygwin.mt
gdb/gdbserver/ChangeLog
gdb/gdbserver/inferiors.c
gdb/gdbserver/remote-utils.c
gdb/gdbserver/server.c
gdb/gdbserver/server.h
gdb/gdbserver/win32-low.c
gdb/testsuite/ChangeLog
gdb/testsuite/gdb.base/unload.c
gdb/testsuite/gdb.base/unload.exp

index 0e2f5ff132b72816bfbbb0afb8df5b4e4971619f..50e50edece8814dba2f433c66d3035c8b8bc0c93 100644 (file)
@@ -1,3 +1,11 @@
+2007-07-17  Pedro Alves  <pedro_alves@portugalmail.pt>
+           Daniel Jacobowitz  <dan@codesourcery.com>
+
+       * config/i386/cygwin.mt (TDEPFILES): Add solib-target.o.
+       * coff-pe-read.c (read_pe_exported_syms): Delete verbose
+       printf.
+       * NEWS: Mention gdbserver DLL support.
+
 2007-07-17  Daniel Jacobowitz  <dan@codesourcery.com>
 
        * dwarf2read.c (dwarf_decode_lines): Detect address size mismatches.
index b3bd08a913ec1584ea73d61f621a61483ca374f9..b003f63149489e7834bd184a70b9cc128cae8b0b 100644 (file)
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -54,6 +54,9 @@ packet, this response allows GDB to debug shared libraries on targets
 where the operating system manages the list of loaded libraries (e.g.
 Windows and SymbianOS).
 
+* The GDB remote stub, gdbserver, now supports dynamic link libraries
+(DLLs) on Windows and Windows CE targets.
+
 * New commands
 
 set remoteflow
index bf92b4bf6551e2ee1b895e965f1d5ff2d7046a5e..497c9513f7bff33b213b34dec0647b4bd252cabc 100644 (file)
@@ -309,9 +309,6 @@ read_pe_exported_syms (struct objfile *objfile)
        += ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile));
     }
 
-  printf_filtered (_("Minimal symbols from %s..."), dll_name);
-  wrap_here ("");
-
   /* Truncate name at first dot. Should maybe also convert to all
      lower case for convenience on Windows. */
   read_pe_truncate_name (dll_name);
index 555b8bf0431761a4fc989ab3d21c8335d7798135..47cfbaaacb2273f30eb4981049c038b93b1d9b0f 100644 (file)
@@ -1,2 +1,3 @@
 # Target: Intel 386 run win32
-TDEPFILES= i386-tdep.o i386-cygwin-tdep.o i387-tdep.o
+TDEPFILES= i386-tdep.o i386-cygwin-tdep.o i387-tdep.o \
+          solib-target.o
index ee411702401d8cad45f4234b610980c0302f0cb8..7c58e030eab3401c5be5df7f421b785ab481f1d2 100644 (file)
@@ -1,3 +1,32 @@
+2007-07-17  Pedro Alves  <pedro_alves@portugalmail.pt>
+           Daniel Jacobowitz  <dan@codesourcery.com>
+
+       * inferiors.c (all_dlls, dlls_changed, get_dll): New.
+       (add_thread): Minor cleanups.
+       (clear_inferiors): Move lower in the file.  Clear the DLL
+       list.
+       (free_one_dll, match_dll, loaded_dll, unloaded_dll, clear_list): New.
+       * remote-utils.c (prepare_resume_reply): Check dlls_changed.
+       (xml_escape_text): New.
+       * server.c (handle_query): Handle qXfer:libraries:read.  Report it
+       for qSupported.
+       (handle_v_cont): Report errors.
+       (gdbserver_version): Update.
+       (main): Correct size of own_buf.  Do not report initial DLL events.
+       * server.h (struct dll_info, all_dlls, dlls_changed, loaded_dll)
+       (unloaded_dll, xml_escape_text): New.
+       * win32-low.c (enum target_waitkind): Update comments.
+       (win32_add_one_solib, get_image_name, winapi_EnumProcessModules)
+       (winapi_GetModuleInformation, winapi_GetModuleFileNameExA)
+       (win32_EnumProcessModules, win32_GetModuleInformation)
+       (win32_GetModuleFileNameExA, load_psapi, psapi_get_dll_name)
+       (winapi_CreateToolhelp32Snapshot, winapi_Module32First)
+       (winapi_Module32Next, win32_CreateToolhelp32Snapshot)
+       (win32_Module32First, win32_Module32Next, load_toolhelp)
+       (toolhelp_get_dll_name, handle_load_dll, handle_unload_dll): New.
+       (get_child_debug_event): Handle DLL events.
+       (win32_wait): Likewise.
+
 2007-07-12  Daniel Jacobowitz  <dan@codesourcery.com>
 
        * configure.srv: Set srv_linux_regsets for sh*-*-linux*.
index 6262d7e812a3dacebda2a24946b760ec62459a7b..c73bf452e0aeadec95dbaf8cf33483241f591be8 100644 (file)
@@ -33,10 +33,13 @@ struct thread_info
 };
 
 struct inferior_list all_threads;
+struct inferior_list all_dlls;
+int dlls_changed;
 
 struct thread_info *current_inferior;
 
 #define get_thread(inf) ((struct thread_info *)(inf))
+#define get_dll(inf) ((struct dll_info *)(inf))
 
 void
 add_inferior_to_list (struct inferior_list *list,
@@ -109,15 +112,14 @@ remove_inferior (struct inferior_list *list,
 void
 add_thread (unsigned long thread_id, void *target_data, unsigned int gdb_id)
 {
-  struct thread_info *new_thread
-    = (struct thread_info *) malloc (sizeof (*new_thread));
+  struct thread_info *new_thread = malloc (sizeof (*new_thread));
 
   memset (new_thread, 0, sizeof (*new_thread));
 
   new_thread->entry.id = thread_id;
 
   add_inferior_to_list (&all_threads, & new_thread->entry);
-  
+
   if (current_inferior == NULL)
     current_inferior = new_thread;
 
@@ -187,14 +189,6 @@ remove_thread (struct thread_info *thread)
   free_one_thread (&thread->entry);
 }
 
-void
-clear_inferiors (void)
-{
-  for_each_inferior (&all_threads, free_one_thread);
-
-  all_threads.head = all_threads.tail = NULL;
-}
-
 struct inferior_list_entry *
 find_inferior (struct inferior_list *list,
               int (*func) (struct inferior_list_entry *, void *), void *arg)
@@ -249,3 +243,80 @@ set_inferior_regcache_data (struct thread_info *inferior, void *data)
 {
   inferior->regcache_data = data;
 }
+
+static void
+free_one_dll (struct inferior_list_entry *inf)
+{
+  struct dll_info *dll = get_dll (inf);
+  if (dll->name != NULL)
+    free (dll->name);
+  free (dll);
+}
+
+/* Find a DLL with the same name and/or base address.  A NULL name in
+   the key is ignored; so is an all-ones base address.  */
+
+static int
+match_dll (struct inferior_list_entry *inf, void *arg)
+{
+  struct dll_info *iter = (void *) inf;
+  struct dll_info *key = arg;
+
+  if (key->base_addr != ~(CORE_ADDR) 0
+      && iter->base_addr == key->base_addr)
+    return 1;
+  else if (key->name != NULL
+          && iter->name != NULL
+          && strcmp (key->name, iter->name) == 0)
+    return 1;
+
+  return 0;
+}
+
+/* Record a newly loaded DLL at BASE_ADDR.  */
+
+void
+loaded_dll (const char *name, CORE_ADDR base_addr)
+{
+  struct dll_info *new_dll = malloc (sizeof (*new_dll));
+  memset (new_dll, 0, sizeof (*new_dll));
+
+  new_dll->entry.id = -1;
+
+  new_dll->name = strdup (name);
+  new_dll->base_addr = base_addr;
+
+  add_inferior_to_list (&all_dlls, &new_dll->entry);
+  dlls_changed = 1;
+}
+
+/* Record that the DLL with NAME and BASE_ADDR has been unloaded.  */
+
+void
+unloaded_dll (const char *name, CORE_ADDR base_addr)
+{
+  struct dll_info *dll;
+  struct dll_info key_dll;
+
+  /* Be careful not to put the key DLL in any list.  */
+  key_dll.name = (char *) name;
+  key_dll.base_addr = base_addr;
+
+  dll = (void *) find_inferior (&all_dlls, match_dll, &key_dll);
+  remove_inferior (&all_dlls, &dll->entry);
+  free_one_dll (&dll->entry);
+  dlls_changed = 1;
+}
+
+#define clear_list(LIST) \
+  do { (LIST)->head = (LIST)->tail = NULL; } while (0)
+
+void
+clear_inferiors (void)
+{
+  for_each_inferior (&all_threads, free_one_thread);
+  for_each_inferior (&all_dlls, free_one_dll);
+
+  clear_list (&all_threads);
+  clear_list (&all_dlls);
+}
index 9c407aaac6c35a2af2c08406a27e80369d9c205e..bd1b482ada84fd5c0fa8193fd855b78ea000cadd 100644 (file)
@@ -965,6 +965,13 @@ prepare_resume_reply (char *buf, char status, unsigned char sig)
              old_thread_from_wait = thread_from_wait;
            }
        }
+
+      if (dlls_changed)
+       {
+         strcpy (buf, "library:;");
+         buf += strlen (buf);
+         dlls_changed = 0;
+       }
     }
   /* For W and X, we're done.  */
   *buf++ = 0;
@@ -1172,3 +1179,65 @@ monitor_output (const char *msg)
   putpkt (buf);
   free (buf);
 }
+
+/* Return a malloc allocated string with special characters from TEXT
+   replaced by entity references.  */
+
+char *
+xml_escape_text (const char *text)
+{
+  char *result;
+  int i, special;
+
+  /* Compute the length of the result.  */
+  for (i = 0, special = 0; text[i] != '\0'; i++)
+    switch (text[i])
+      {
+      case '\'':
+      case '\"':
+       special += 5;
+       break;
+      case '&':
+       special += 4;
+       break;
+      case '<':
+      case '>':
+       special += 3;
+       break;
+      default:
+       break;
+      }
+
+  /* Expand the result.  */
+  result = malloc (i + special + 1);
+  for (i = 0, special = 0; text[i] != '\0'; i++)
+    switch (text[i])
+      {
+      case '\'':
+       strcpy (result + i + special, "&apos;");
+       special += 5;
+       break;
+      case '\"':
+       strcpy (result + i + special, "&quot;");
+       special += 5;
+       break;
+      case '&':
+       strcpy (result + i + special, "&amp;");
+       special += 4;
+       break;
+      case '<':
+       strcpy (result + i + special, "&lt;");
+       special += 3;
+       break;
+      case '>':
+       strcpy (result + i + special, "&gt;");
+       special += 3;
+       break;
+      default:
+       result[i + special] = text[i];
+       break;
+      }
+  result[i + special] = '\0';
+
+  return result;
+}
index bee1256403c37485a896a49d4cb094345ceb8da1..9225f663e2a8c8ee29061f0baeea628fd0765d1c 100644 (file)
@@ -458,12 +458,80 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p)
       return;
     }
 
+  if (strncmp ("qXfer:libraries:read:", own_buf, 21) == 0)
+    {
+      CORE_ADDR ofs;
+      unsigned int len, total_len;
+      char *document, *p;
+      struct inferior_list_entry *dll_ptr;
+      char *annex;
+
+      /* Reject any annex; grab the offset and length.  */
+      if (decode_xfer_read (own_buf + 21, &annex, &ofs, &len) < 0
+         || annex[0] != '\0')
+       {
+         strcpy (own_buf, "E00");
+         return;
+       }
+
+      /* Over-estimate the necessary memory.  Assume that every character
+        in the library name must be escaped.  */
+      total_len = 64;
+      for (dll_ptr = all_dlls.head; dll_ptr != NULL; dll_ptr = dll_ptr->next)
+       total_len += 128 + 6 * strlen (((struct dll_info *) dll_ptr)->name);
+
+      document = malloc (total_len);
+      strcpy (document, "<library-list>\n");
+      p = document + strlen (document);
+
+      for (dll_ptr = all_dlls.head; dll_ptr != NULL; dll_ptr = dll_ptr->next)
+       {
+         struct dll_info *dll = (struct dll_info *) dll_ptr;
+         char *name;
+
+         strcpy (p, "  <library name=\"");
+         p = p + strlen (p);
+         name = xml_escape_text (dll->name);
+         strcpy (p, name);
+         free (name);
+         p = p + strlen (p);
+         strcpy (p, "\"><segment address=\"");
+         p = p + strlen (p);
+         sprintf (p, "0x%lx", (long) dll->base_addr);
+         p = p + strlen (p);
+         strcpy (p, "\"/></library>\n");
+         p = p + strlen (p);
+       }
+
+      strcpy (p, "</library-list>\n");
+
+      total_len = strlen (document);
+      if (len > PBUFSIZ - 2)
+       len = PBUFSIZ - 2;
+
+      if (ofs > total_len)
+       write_enn (own_buf);
+      else if (len < total_len - ofs)
+       *new_packet_len_p = write_qxfer_response (own_buf, document + ofs,
+                                                 len, 1);
+      else
+       *new_packet_len_p = write_qxfer_response (own_buf, document + ofs,
+                                                 total_len - ofs, 0);
+
+      free (document);
+      return;
+    }
+
   /* Protocol features query.  */
   if (strncmp ("qSupported", own_buf, 10) == 0
       && (own_buf[10] == ':' || own_buf[10] == '\0'))
     {
       sprintf (own_buf, "PacketSize=%x;QPassSignals+", PBUFSIZ - 1);
 
+      /* We do not have any hook to indicate whether the target backend
+        supports qXfer:libraries:read, so always report it.  */
+      strcat (own_buf, ";qXfer:libraries:read+");
+
       if (the_target->read_auxv != NULL)
        strcat (own_buf, ";qXfer:auxv:read+");
      
@@ -696,8 +764,7 @@ handle_v_cont (char *own_buf, char *status, int *signal)
   return;
 
 err:
-  /* No other way to report an error... */
-  strcpy (own_buf, "");
+  write_enn (own_buf);
   free (resume_info);
   return;
 }
@@ -753,7 +820,7 @@ static void
 gdbserver_version (void)
 {
   printf ("GNU gdbserver %s\n"
-         "Copyright (C) 2006 Free Software Foundation, Inc.\n"
+         "Copyright (C) 2007 Free Software Foundation, Inc.\n"
          "gdbserver is free software, covered by the GNU General Public License.\n"
          "This gdbserver was configured as \"%s\"\n",
          version, host_name);
@@ -824,7 +891,7 @@ main (int argc, char *argv[])
 
   initialize_low ();
 
-  own_buf = malloc (PBUFSIZ);
+  own_buf = malloc (PBUFSIZ + 1);
   mem_buf = malloc (PBUFSIZ);
 
   if (pid == 0)
@@ -833,6 +900,10 @@ main (int argc, char *argv[])
       signal = start_inferior (&argv[2], &status);
 
       /* We are now stopped at the first instruction of the target process */
+
+      /* Don't report shared library events on the initial connection,
+        even if some libraries are preloaded.  */
+      dlls_changed = 0;
     }
   else
     {
index 573bde28935ba2154b395e2745e6750320073874..ea7666e7a4cda66d6f3f5e3963f08e746d5bd0f9 100644 (file)
@@ -91,6 +91,13 @@ struct inferior_list_entry
 /* Opaque type for user-visible threads.  */
 struct thread_info;
 
+struct dll_info
+{
+  struct inferior_list_entry entry;
+  char *name;
+  CORE_ADDR base_addr;
+};
+
 #include "regcache.h"
 #include "gdb/signals.h"
 
@@ -104,6 +111,9 @@ void initialize_low ();
 /* From inferiors.c.  */
 
 extern struct inferior_list all_threads;
+extern struct inferior_list all_dlls;
+extern int dlls_changed;
+
 void add_inferior_to_list (struct inferior_list *list,
                           struct inferior_list_entry *new_inferior);
 void for_each_inferior (struct inferior_list *list,
@@ -132,6 +142,9 @@ void set_inferior_regcache_data (struct thread_info *, void *);
 void change_inferior_id (struct inferior_list *list,
                         unsigned long new_id);
 
+void loaded_dll (const char *name, CORE_ADDR base_addr);
+void unloaded_dll (const char *name, CORE_ADDR base_addr);
+
 /* Public variables in server.c */
 
 extern unsigned long cont_thread;
@@ -190,6 +203,8 @@ int look_up_one_symbol (const char *name, CORE_ADDR *addrp);
 
 void monitor_output (const char *msg);
 
+char *xml_escape_text (const char *text);
+
 /* Functions from ``signals.c''.  */
 enum target_signal target_signal_from_host (int hostsig);
 int target_signal_to_host_p (enum target_signal oursig);
index 161cadf69044110bd7385939fd3d9c46b9f743a7..1382cb83a957aa291d40ff6ff3ffd379b977021b 100644 (file)
@@ -29,6 +29,7 @@
 #include <windows.h>
 #include <winnt.h>
 #include <imagehlp.h>
+#include <tlhelp32.h>
 #include <psapi.h>
 #include <sys/param.h>
 #include <malloc.h>
@@ -202,8 +203,8 @@ enum target_waitkind
      value.sig.  */
   TARGET_WAITKIND_STOPPED,
 
-  /* The program is letting us know that it dynamically loaded something
-     (e.g. it called load(2) on AIX).  */
+  /* The program is letting us know that it dynamically loaded
+     or unloaded something.  */
   TARGET_WAITKIND_LOADED,
 
   /* The program has exec'ed a new executable file.  The new file's
@@ -772,6 +773,316 @@ win32_resume (struct thread_resume *resume_info)
   child_continue (continue_status, tid);
 }
 
+static void
+win32_add_one_solib (const char *name, CORE_ADDR load_addr)
+{
+  char buf[MAX_PATH + 1];
+  char buf2[MAX_PATH + 1];
+
+#ifdef _WIN32_WCE
+  WIN32_FIND_DATA w32_fd;
+  WCHAR wname[MAX_PATH + 1];
+  mbstowcs (wname, name, MAX_PATH);
+  HANDLE h = FindFirstFile (wname, &w32_fd);
+#else
+  WIN32_FIND_DATAA w32_fd;
+  HANDLE h = FindFirstFileA (name, &w32_fd);
+#endif
+
+  if (h == INVALID_HANDLE_VALUE)
+    strcpy (buf, name);
+  else
+    {
+      FindClose (h);
+      strcpy (buf, name);
+#ifndef _WIN32_WCE
+      {
+       char cwd[MAX_PATH + 1];
+       char *p;
+       if (GetCurrentDirectoryA (MAX_PATH + 1, cwd))
+         {
+           p = strrchr (buf, '\\');
+           if (p)
+             p[1] = '\0';
+           SetCurrentDirectoryA (buf);
+           GetFullPathNameA (w32_fd.cFileName, MAX_PATH, buf, &p);
+           SetCurrentDirectoryA (cwd);
+         }
+      }
+#endif
+    }
+
+#ifdef __CYGWIN__
+  cygwin_conv_to_posix_path (buf, buf2);
+#else
+  strcpy (buf2, buf);
+#endif
+
+  loaded_dll (buf2, load_addr);
+}
+
+static char *
+get_image_name (HANDLE h, void *address, int unicode)
+{
+  static char buf[(2 * MAX_PATH) + 1];
+  DWORD size = unicode ? sizeof (WCHAR) : sizeof (char);
+  char *address_ptr;
+  int len = 0;
+  char b[2];
+  DWORD done;
+
+  /* Attempt to read the name of the dll that was detected.
+     This is documented to work only when actively debugging
+     a program.  It will not work for attached processes. */
+  if (address == NULL)
+    return NULL;
+
+#ifdef _WIN32_WCE
+  /* Windows CE reports the address of the image name,
+     instead of an address of a pointer into the image name.  */
+  address_ptr = address;
+#else
+  /* See if we could read the address of a string, and that the
+     address isn't null. */
+  if (!ReadProcessMemory (h, address,  &address_ptr,
+                         sizeof (address_ptr), &done)
+      || done != sizeof (address_ptr)
+      || !address_ptr)
+    return NULL;
+#endif
+
+  /* Find the length of the string */
+  while (ReadProcessMemory (h, address_ptr + len++ * size, &b, size, &done)
+        && (b[0] != 0 || b[size - 1] != 0) && done == size)
+    continue;
+
+  if (!unicode)
+    ReadProcessMemory (h, address_ptr, buf, len, &done);
+  else
+    {
+      WCHAR *unicode_address = (WCHAR *) alloca (len * sizeof (WCHAR));
+      ReadProcessMemory (h, address_ptr, unicode_address, len * sizeof (WCHAR),
+                        &done);
+
+      WideCharToMultiByte (CP_ACP, 0, unicode_address, len, buf, len, 0, 0);
+    }
+
+  return buf;
+}
+
+typedef BOOL (WINAPI *winapi_EnumProcessModules) (HANDLE, HMODULE *,
+                                                 DWORD, LPDWORD);
+typedef BOOL (WINAPI *winapi_GetModuleInformation) (HANDLE, HMODULE,
+                                                   LPMODULEINFO, DWORD);
+typedef DWORD (WINAPI *winapi_GetModuleFileNameExA) (HANDLE, HMODULE,
+                                                    LPSTR, DWORD);
+
+static winapi_EnumProcessModules win32_EnumProcessModules;
+static winapi_GetModuleInformation win32_GetModuleInformation;
+static winapi_GetModuleFileNameExA win32_GetModuleFileNameExA;
+
+static BOOL
+load_psapi (void)
+{
+  static int psapi_loaded = 0;
+  static HMODULE dll = NULL;
+
+  if (!psapi_loaded)
+    {
+      psapi_loaded = 1;
+      dll = LoadLibrary (TEXT("psapi.dll"));
+      if (!dll)
+       return FALSE;
+      win32_EnumProcessModules =
+             GETPROCADDRESS (dll, EnumProcessModules);
+      win32_GetModuleInformation =
+             GETPROCADDRESS (dll, GetModuleInformation);
+      win32_GetModuleFileNameExA =
+             GETPROCADDRESS (dll, GetModuleFileNameExA);
+    }
+
+  return (win32_EnumProcessModules != NULL
+         && win32_GetModuleInformation != NULL
+         && win32_GetModuleFileNameExA != NULL);
+}
+
+static int
+psapi_get_dll_name (DWORD BaseAddress, char *dll_name_ret)
+{
+  DWORD len;
+  MODULEINFO mi;
+  size_t i;
+  HMODULE dh_buf[1];
+  HMODULE *DllHandle = dh_buf;
+  DWORD cbNeeded;
+  BOOL ok;
+
+  if (!load_psapi ())
+    goto failed;
+
+  cbNeeded = 0;
+  ok = (*win32_EnumProcessModules) (current_process_handle,
+                                   DllHandle,
+                                   sizeof (HMODULE),
+                                   &cbNeeded);
+
+  if (!ok || !cbNeeded)
+    goto failed;
+
+  DllHandle = (HMODULE *) alloca (cbNeeded);
+  if (!DllHandle)
+    goto failed;
+
+  ok = (*win32_EnumProcessModules) (current_process_handle,
+                                   DllHandle,
+                                   cbNeeded,
+                                   &cbNeeded);
+  if (!ok)
+    goto failed;
+
+  for (i = 0; i < ((size_t) cbNeeded / sizeof (HMODULE)); i++)
+    {
+      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 ((DWORD) (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;
+       }
+    }
+
+failed:
+  dll_name_ret[0] = '\0';
+  return 0;
+}
+
+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;
+
+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 = GetModuleHandle (_T("COREDLL.DLL"));
+#endif
+      if (!dll)
+       return FALSE;
+
+      win32_CreateToolhelp32Snapshot =
+       GETPROCADDRESS (dll, CreateToolhelp32Snapshot);
+      win32_Module32First = GETPROCADDRESS (dll, Module32First);
+      win32_Module32Next = GETPROCADDRESS (dll, Module32Next);
+    }
+
+  return (win32_CreateToolhelp32Snapshot != NULL
+         && win32_Module32First != NULL
+         && win32_Module32Next != NULL);
+}
+
+static int
+toolhelp_get_dll_name (DWORD BaseAddress, char *dll_name_ret)
+{
+  HANDLE snapshot_module;
+  MODULEENTRY32 modEntry = { sizeof (MODULEENTRY32) };
+
+  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))
+    goto failed;
+
+  while (win32_Module32Next (snapshot_module, &modEntry))
+    if ((DWORD) modEntry.modBaseAddr == BaseAddress)
+      {
+#ifdef UNICODE
+       wcstombs (dll_name_ret, modEntry.szExePath, MAX_PATH + 1);
+#else
+       strcpy (dll_name_ret, modEntry.szExePath);
+#endif
+       CloseHandle (snapshot_module);
+       return 1;
+      }
+
+failed:
+  CloseHandle (snapshot_module);
+  return 0;
+}
+
+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;
+  DWORD load_addr;
+
+  dll_buf[0] = dll_buf[sizeof (dll_buf) - 1] = '\0';
+
+  if (!psapi_get_dll_name ((DWORD) (event->lpBaseOfDll), dll_buf)
+      && !toolhelp_get_dll_name ((DWORD) (event->lpBaseOfDll), dll_buf))
+    dll_buf[0] = dll_buf[sizeof (dll_buf) - 1] = '\0';
+
+  dll_name = dll_buf;
+
+  if (*dll_name == '\0')
+    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
+     the offset from 0 of the first byte in an image - because
+     of the file header and the section alignment. */
+
+  load_addr = (DWORD) event->lpBaseOfDll + 0x1000;
+  win32_add_one_solib (dll_name, load_addr);
+}
+
+static void
+handle_unload_dll (void)
+{
+  CORE_ADDR load_addr =
+         (CORE_ADDR) (DWORD) current_event.u.UnloadDll.lpBaseOfDll;
+  load_addr += 0x1000;
+  unloaded_dll (NULL, load_addr);
+}
+
 static void
 handle_exception (struct target_waitstatus *ourstatus)
 {
@@ -963,9 +1274,10 @@ get_child_debug_event (struct target_waitstatus *ourstatus)
                (unsigned) current_event.dwProcessId,
                (unsigned) current_event.dwThreadId));
       CloseHandle (current_event.u.LoadDll.hFile);
+      handle_load_dll ();
 
       ourstatus->kind = TARGET_WAITKIND_LOADED;
-      ourstatus->value.integer = 0;
+      ourstatus->value.sig = TARGET_SIGNAL_TRAP;
       break;
 
     case UNLOAD_DLL_DEBUG_EVENT:
@@ -973,6 +1285,9 @@ get_child_debug_event (struct target_waitstatus *ourstatus)
                "for pid=%d tid=%x\n",
                (unsigned) current_event.dwProcessId,
                (unsigned) current_event.dwThreadId));
+      handle_unload_dll ();
+      ourstatus->kind = TARGET_WAITKIND_LOADED;
+      ourstatus->value.sig = TARGET_SIGNAL_TRAP;
       break;
 
     case EXCEPTION_DEBUG_EVENT:
@@ -1035,6 +1350,7 @@ win32_wait (char *status)
 
          return our_status.value.integer;
        case TARGET_WAITKIND_STOPPED:
+       case TARGET_WAITKIND_LOADED:
          OUTMSG2 (("Child Stopped with signal = %d \n",
                    our_status.value.sig));
 
@@ -1042,12 +1358,20 @@ win32_wait (char *status)
 
          child_fetch_inferior_registers (-1);
 
+         if (our_status.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;
+           }
+
          return our_status.value.sig;
        default:
          OUTMSG (("Ignoring unknown internal event, %d\n", our_status.kind));
          /* fall-through */
        case TARGET_WAITKIND_SPURIOUS:
-       case TARGET_WAITKIND_LOADED:
        case TARGET_WAITKIND_EXECD:
          /* do nothing, just continue */
          child_continue (DBG_CONTINUE, -1);
index 79994ccea0675db32870e16805bb6af3d376de0d..8ec0434e34b3c3cdb8c6ceaf457819625ae3e9a9 100644 (file)
@@ -1,3 +1,11 @@
+2007-07-17  Pedro Alves  <pedro_alves@portugalmail.pt>
+           Daniel Jacobowitz  <dan@codesourcery.com>
+
+       * gdb.base/unload.c (dlopen, dlsym, dlclose, dlerror): Define
+       for __WIN32__.
+       (SHLIB_NAME): Delete definition.  Always pass dlerror to fprintf.
+       * gdb.base/unload.exp: Use shared library test routines.
+
 2007-07-03  Markus Deuling  <deuling@de.ibm.com>
 
        * gdb.base/solib-symbol.exp: New file (testcase multiple symbol lookup).
index 799bb55584a1d640cf479cd53f4e2d6c544408fc..f8c8046e9831d2d4fd4357c6d8a90208a6b265a6 100644 (file)
 
 #include <stdio.h>
 #include <stdlib.h>
+
+#ifdef __WIN32__
+#include <windows.h>
+#define dlopen(name, mode) LoadLibrary (name)
+#define dlsym(handle, func) GetProcAddress (handle, func)
+#define dlclose(handle) FreeLibrary (handle)
+#define dlerror() "error %d occurred", GetLastError ()
+#else
 #include <dlfcn.h>
+#endif
 
 int k = 0;
 
-#define SHLIB_NAME SHLIB_DIR "/unloadshr.sl"
-
 int main()
 {
   void *handle;
@@ -32,11 +39,10 @@ int main()
   const char *msg;
 
   handle = dlopen (SHLIB_NAME, RTLD_LAZY);
-  msg = dlerror ();
   
   if (!handle)
     {
-      fprintf (stderr, msg);
+      fprintf (stderr, dlerror ());
       exit (1);
     }
 
index 1b731f01121c3819b22b21bcf49dc45c53a9e90e..78090b93249cd0e8219e68b78f63287bf1cb2ef1 100644 (file)
@@ -30,37 +30,28 @@ if {[skip_shlib_tests]} {
     return 0
 }
 
-# TODO: Use LoadLibrary on these targets instead of dlopen.
-if {([istarget arm*-*-symbianelf*]
-     || [istarget *-*-mingw*]
-     || [istarget *-*-cygwin*]
-     || [istarget *-*-pe*])} {
+# TODO: Use LoadLibrary on this target instead of dlopen.
+if {[istarget arm*-*-symbianelf*]} {
     return 0
 }
 
 set testfile "unload"
 set libfile "unloadshr"
+set libname "${libfile}.sl"
 set libsrcfile ${libfile}.c
 set srcfile $srcdir/$subdir/$testfile.c
 set binfile $objdir/$subdir/$testfile
 set shlibdir ${objdir}/${subdir}
 set libsrc  $srcdir/$subdir/$libfile.c
-set lib_sl  $objdir/$subdir/$libfile.sl
-
-set lib_opts debug
-set exec_opts [list debug additional_flags=-DSHLIB_DIR\=\"${shlibdir}\"]
-
-switch -glob [istarget] {
-    "hppa*-hp-hpux*" { }
-    "*-*-linux*"     { lappend exec_opts "libs=-ldl" }
-    "*-*-solaris*"   { lappend exec_opts "libs=-ldl" }
-    default          { }
-}
+set lib_sl  $objdir/$subdir/$libname
 
 if [get_compiler_info ${binfile}] {
     return -1
 }
 
+set lib_opts debug
+set exec_opts [list debug shlib_load additional_flags=-DSHLIB_NAME\=\"${libname}\"]
+
 if { [gdb_compile_shlib $libsrc $lib_sl $lib_opts] != ""
      || [gdb_compile $srcfile $binfile executable $exec_opts] != ""} {
     untested "Couldn't compile $libsrc or $srcfile."