This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[RFA] gdbserver crash when running 32bits executables on 64bits windows.


From: Joel Brobecker  <brobecker@adacore.com>

Hello,

This crash was observed on Windows64 machines running 32bit executables
through gdbserver.  In other words, we had on the same machine gdbserver
controlling the inferior, and GDB connected to gdbserver with "target
remote".

The problem turns out to be caused by a spurious unloaded-dll event.
These events occur during the startup phase, and they do not correspond
to any DLL load event that we might have received earlier.  As a result,
we crash trying to dereference a NULL dll_info returned by find_inferior.

One theory that was floated to explain this is that this may be caused
by the WOW64 layer (the layer that interfaces the 32bit and 64bit worlds).
Perhaps it is loading/unloading data and/or code as DLL directly from
memory? Perhaps a plain kernel bug? We couldn't find much info on this
on the web, so it's hard to tell for sure.

Since it is possible for us to receive these spurious unload events,
we added a check, and returned without further ado when we could not
locate the associated DLL.

gdbserver/ChangeLog:

        * inferiors.c (find_inferior): Add function documentation.
        (unloaded_dll): Handle the case where the unloaded dll has not
        been previously registered in the dll list.

I tested this change on x86_64-linux, using the procedure outlined
in the Wiki for doing native gdbserver testing.  I also tested this
change on x86-windows (XP) and x86_64-windows (Windows 2008 and Windows 7)
using the AdaCore testsuite - for x86_64-windows, I used a 32bit port,
obviously.

OK to apply?

Thanks,
-- 
Joel

---
 gdb/gdbserver/ChangeLog.GNAT |    9 +++++++++
 gdb/gdbserver/inferiors.c    |   25 ++++++++++++++++++++++---
 2 files changed, 31 insertions(+), 3 deletions(-)

diff --git a/gdb/gdbserver/inferiors.c b/gdb/gdbserver/inferiors.c
index c1a1881..097326d 100644
--- a/gdb/gdbserver/inferiors.c
+++ b/gdb/gdbserver/inferiors.c
@@ -249,6 +249,9 @@ remove_thread (struct thread_info *thread)
   free_one_thread (&thread->entry);
 }
 
+/* Find the first inferior_list_entry E in LIST for which FUNC (E, ARG)
+   returns non-zero.  If no entry is found then return NULL.  */
+
 struct inferior_list_entry *
 find_inferior (struct inferior_list *list,
 	       int (*func) (struct inferior_list_entry *, void *), void *arg)
@@ -366,9 +369,25 @@ unloaded_dll (const char *name, CORE_ADDR base_addr)
   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;
+
+  if (dll == NULL)
+    /* For some inferiors we might get unloaded_dll events without having
+       a corresponding loaded_dll.  In that case, the dll cannot be found
+       in ALL_DLL, and there is nothing further for us to do.
+
+       This has been observed when running 32bit executables on Windows64
+       (i.e. through WOW64, the interface between the 32bits and 64bits
+       worlds).  In that case, the inferior always does some strange
+       unloading of unnamed dll.  */
+    return;
+  else
+    {
+      /* DLL has been found so remove the entry and free associated
+         resources.  */
+      remove_inferior (&all_dlls, &dll->entry);
+      free_one_dll (&dll->entry);
+      dlls_changed = 1;
+    }
 }
 
 #define clear_list(LIST) \
-- 
1.6.3.3


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]