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 0e2f5ff..50e50ed 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.
 2007-07-17  Daniel Jacobowitz  <dan@codesourcery.com>
 
        * dwarf2read.c (dwarf_decode_lines): Detect address size mismatches.
index b3bd08a..b003f63 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).
 
 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
 * New commands
 
 set remoteflow
index bf92b4b..497c951 100644 (file)
@@ -309,9 +309,6 @@ read_pe_exported_syms (struct objfile *objfile)
        += ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (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);
   /* Truncate name at first dot. Should maybe also convert to all
      lower case for convenience on Windows. */
   read_pe_truncate_name (dll_name);
index 555b8bf..47cfbaa 100644 (file)
@@ -1,2 +1,3 @@
 # Target: Intel 386 run win32
 # 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 ee41170..7c58e03 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*.
 2007-07-12  Daniel Jacobowitz  <dan@codesourcery.com>
 
        * configure.srv: Set srv_linux_regsets for sh*-*-linux*.
index 6262d7e..c73bf45 100644 (file)
@@ -33,10 +33,13 @@ struct thread_info
 };
 
 struct inferior_list all_threads;
 };
 
 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))
 
 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,
 
 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)
 {
 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);
 
   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;
 
   if (current_inferior == NULL)
     current_inferior = new_thread;
 
@@ -187,14 +189,6 @@ remove_thread (struct thread_info *thread)
   free_one_thread (&thread->entry);
 }
 
   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)
 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;
 }
 {
   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 9c407aa..bd1b482 100644 (file)
@@ -965,6 +965,13 @@ prepare_resume_reply (char *buf, char status, unsigned char sig)
              old_thread_from_wait = thread_from_wait;
            }
        }
              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;
     }
   /* For W and X, we're done.  */
   *buf++ = 0;
@@ -1172,3 +1179,65 @@ monitor_output (const char *msg)
   putpkt (buf);
   free (buf);
 }
   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 bee1256..9225f66 100644 (file)
@@ -458,12 +458,80 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p)
       return;
     }
 
       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);
 
   /* 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+");
      
       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:
   return;
 
 err:
-  /* No other way to report an error... */
-  strcpy (own_buf, "");
+  write_enn (own_buf);
   free (resume_info);
   return;
 }
   free (resume_info);
   return;
 }
@@ -753,7 +820,7 @@ static void
 gdbserver_version (void)
 {
   printf ("GNU gdbserver %s\n"
 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);
          "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 ();
 
 
   initialize_low ();
 
-  own_buf = malloc (PBUFSIZ);
+  own_buf = malloc (PBUFSIZ + 1);
   mem_buf = malloc (PBUFSIZ);
 
   if (pid == 0)
   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 */
       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
     {
     }
   else
     {
index 573bde2..ea7666e 100644 (file)
@@ -91,6 +91,13 @@ struct inferior_list_entry
 /* Opaque type for user-visible threads.  */
 struct thread_info;
 
 /* 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"
 
 #include "regcache.h"
 #include "gdb/signals.h"
 
@@ -104,6 +111,9 @@ void initialize_low ();
 /* From inferiors.c.  */
 
 extern struct inferior_list all_threads;
 /* 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,
 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 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;
 /* 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);
 
 
 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);
 /* Functions from ``signals.c''.  */
 enum target_signal target_signal_from_host (int hostsig);
 int target_signal_to_host_p (enum target_signal oursig);
index 161cadf..1382cb8 100644 (file)
@@ -29,6 +29,7 @@
 #include <windows.h>
 #include <winnt.h>
 #include <imagehlp.h>
 #include <windows.h>
 #include <winnt.h>
 #include <imagehlp.h>
+#include <tlhelp32.h>
 #include <psapi.h>
 #include <sys/param.h>
 #include <malloc.h>
 #include <psapi.h>
 #include <sys/param.h>
 #include <malloc.h>
@@ -202,8 +203,8 @@ enum target_waitkind
      value.sig.  */
   TARGET_WAITKIND_STOPPED,
 
      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
   TARGET_WAITKIND_LOADED,
 
   /* The program has exec'ed a new executable file.  The new file's
@@ -773,6 +774,316 @@ win32_resume (struct thread_resume *resume_info)
 }
 
 static void
 }
 
 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)
 {
   DWORD code = current_event.u.Exception.ExceptionRecord.ExceptionCode;
 handle_exception (struct target_waitstatus *ourstatus)
 {
   DWORD code = current_event.u.Exception.ExceptionRecord.ExceptionCode;
@@ -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);
                (unsigned) current_event.dwProcessId,
                (unsigned) current_event.dwThreadId));
       CloseHandle (current_event.u.LoadDll.hFile);
+      handle_load_dll ();
 
       ourstatus->kind = TARGET_WAITKIND_LOADED;
 
       ourstatus->kind = TARGET_WAITKIND_LOADED;
-      ourstatus->value.integer = 0;
+      ourstatus->value.sig = TARGET_SIGNAL_TRAP;
       break;
 
     case UNLOAD_DLL_DEBUG_EVENT:
       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));
                "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:
       break;
 
     case EXCEPTION_DEBUG_EVENT:
@@ -1035,6 +1350,7 @@ win32_wait (char *status)
 
          return our_status.value.integer;
        case TARGET_WAITKIND_STOPPED:
 
          return our_status.value.integer;
        case TARGET_WAITKIND_STOPPED:
+       case TARGET_WAITKIND_LOADED:
          OUTMSG2 (("Child Stopped with signal = %d \n",
                    our_status.value.sig));
 
          OUTMSG2 (("Child Stopped with signal = %d \n",
                    our_status.value.sig));
 
@@ -1042,12 +1358,20 @@ win32_wait (char *status)
 
          child_fetch_inferior_registers (-1);
 
 
          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:
          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);
        case TARGET_WAITKIND_EXECD:
          /* do nothing, just continue */
          child_continue (DBG_CONTINUE, -1);
index 79994cc..8ec0434 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).
 2007-07-03  Markus Deuling  <deuling@de.ibm.com>
 
        * gdb.base/solib-symbol.exp: New file (testcase multiple symbol lookup).
index 799bb55..f8c8046 100644 (file)
 
 #include <stdio.h>
 #include <stdlib.h>
 
 #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>
 #include <dlfcn.h>
+#endif
 
 int k = 0;
 
 
 int k = 0;
 
-#define SHLIB_NAME SHLIB_DIR "/unloadshr.sl"
-
 int main()
 {
   void *handle;
 int main()
 {
   void *handle;
@@ -32,11 +39,10 @@ int main()
   const char *msg;
 
   handle = dlopen (SHLIB_NAME, RTLD_LAZY);
   const char *msg;
 
   handle = dlopen (SHLIB_NAME, RTLD_LAZY);
-  msg = dlerror ();
   
   if (!handle)
     {
   
   if (!handle)
     {
-      fprintf (stderr, msg);
+      fprintf (stderr, dlerror ());
       exit (1);
     }
 
       exit (1);
     }
 
index 1b731f0..78090b9 100644 (file)
@@ -30,37 +30,28 @@ if {[skip_shlib_tests]} {
     return 0
 }
 
     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"
     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 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
 }
 
 
 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."
 if { [gdb_compile_shlib $libsrc $lib_sl $lib_opts] != ""
      || [gdb_compile $srcfile $binfile executable $exec_opts] != ""} {
     untested "Couldn't compile $libsrc or $srcfile."