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]

[committed] first steps towards making gdb understand cygwin signals


This patch will play nicely with 1.5.20 when it is released.  It is
the first step towards making gdb and cygwin cooperate so that gdb
will recognize cygwin's non-windows-native type signals.

Not all of the code is yet in the Cygwin DLL to completely support this
but this patch should stop the steady trickle of complaints from people
who are confused when the exception handling used by the cygwin DLL is
trapped by gdb since gdb will now no longer see a SEGV from the Cygwin
DLL when this happens.

cgf

2006-02-19  Christopher Faylor  <cgf@timesys.com>

	* win32_nat.c (cygwin_load_start): New variable.
	(cygwin_load_end): Ditto.
	(have_saved_context): Ditto.
	(saved_context): Ditto.
	(max_dll_name_len): Delete obsolete variable.
	(do_win32_fetch_inferior_registers): Use context saved from cygwin1.dll
	if we are in a cygwin signal rather than a windows signal.
	(solib_symbols_add): Detect and store beginning and end of cygwin DLL
	if dll being loaded is the cygwin DLL.
	(register_loaded_dll): Remove calculation of max_dll_name_len.
	(win32_clear_solib): Ditto.
	(handle_load_dll): Delete obsolete variable.  Remove unneeded call to
	solib_add.
	(handle_output_debug_string): Detect and store signal information sent
	by Cygwin here.
	(handle_exception): Silently pass on errors in the cygwin DLL.  Return
	-1 on first pass exception.
	(win32_continue): Remove spurious clearing of continue_status.
	(get_win32_debug_event): Deal differently first chance exception.

Index: win32-nat.c
===================================================================
RCS file: /cvs/uberbaum/gdb/win32-nat.c,v
retrieving revision 1.119
diff -u -p -r1.119 win32-nat.c
--- win32-nat.c	24 Jan 2006 22:09:28 -0000	1.119
+++ win32-nat.c	20 Feb 2006 05:05:56 -0000
@@ -44,6 +44,7 @@
 #include <windows.h>
 #include <imagehlp.h>
 #include <sys/cygwin.h>
+#include <signal.h>
 
 #include "buildsym.h"
 #include "symfile.h"
@@ -63,6 +64,13 @@
 static struct target_ops win32_ops;
 static struct target_so_ops win32_so_ops;
 
+/* The starting and ending address of the cygwin1.dll text segment. */
+static bfd_vma cygwin_load_start;
+static bfd_vma cygwin_load_end;
+
+static int have_saved_context;	/* True if we've saved context from a cygwin signal. */
+static CONTEXT saved_context;	/* Containes the saved context from a cygwin signal. */
+
 /* If we're not using the old Cygwin header file set, define the
    following which never should have been in the generic Win32 API
    headers in the first place since they were our own invention... */
@@ -346,16 +354,27 @@ do_win32_fetch_inferior_registers (int r
 
   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;
+      if (have_saved_context)
+	{
+	  /* Lie about where the program actually is stopped since cygwin has informed us that
+	     we should consider the signal to have occurred at another location which is stored
+	     in "saved_context. */
+	  memcpy (&current_thread->context, &saved_context, __COPY_CONTEXT_SIZE);
+	  have_saved_context = 0;
+	}
+      else
+	{
+	  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;
     }
 
@@ -596,12 +615,10 @@ get_relocated_section_addrs (bfd *abfd, 
     {
       /* Couldn't get the .text section. Weird. */
     }
-
   else if (text_load == (text_vma = bfd_get_section_vma (abfd, text_section)))
     {
       /* DLL wasn't relocated. */
     }
-
   else
     {
       /* Figure out all sections' loaded addresses. The offset here is
@@ -640,6 +657,7 @@ solib_symbols_add (struct so_list *so, C
   static struct objfile *result = NULL;
   char *name = so->so_name;
   bfd *abfd = NULL;
+  char *p;
 
   /* The symbols in a dll are offset by 0x1000, which is the
      the offset from 0 of the first byte in an image - because
@@ -660,8 +678,6 @@ solib_symbols_add (struct so_list *so, C
     {
       if (bfd_check_format (abfd, bfd_object))
 	addrs = get_relocated_section_addrs (abfd, load_addr);
-
-      bfd_close (abfd);
     }
 
   if (addrs)
@@ -683,13 +699,20 @@ solib_symbols_add (struct so_list *so, C
       do_cleanups (my_cleanups);
     }
 
+  p = strchr (so->so_name, '\0') - (sizeof ("/cygwin1.dll") - 1);
+  if (p >= so->so_name && strcasecmp (p, "/cygwin1.dll") == 0)
+    {
+      asection *text = bfd_get_section_by_name (abfd, ".text");
+      cygwin_load_start = bfd_section_vma (abfd, text);
+      cygwin_load_end = cygwin_load_start + bfd_section_size (abfd, text);
+    }
+
+  bfd_close (abfd);
+
   so->symbols_loaded = !!result;
   return;
 }
 
-/* Remember the maximum DLL length for printing in info dll command. */
-static int max_dll_name_len;
-
 static char *
 register_loaded_dll (const char *name, DWORD load_addr, int readsyms)
 {
@@ -733,10 +756,9 @@ register_loaded_dll (const char *name, D
   solib_end->next = so;
   solib_end = so;
   len = strlen (so->so_name);
-  if (len > max_dll_name_len)
-    max_dll_name_len = len;
   if (readsyms)
     solib_symbols_add (so, (CORE_ADDR) load_addr);
+
   return so->so_name;
 }
 
@@ -789,7 +811,6 @@ handle_load_dll (void *dummy)
   LOAD_DLL_DEBUG_INFO *event = &current_event.u.LoadDll;
   char dll_buf[MAX_PATH + 1];
   char *dll_name = NULL;
-  char *p;
 
   dll_buf[0] = dll_buf[sizeof (dll_buf) - 1] = '\0';
 
@@ -804,7 +825,6 @@ handle_load_dll (void *dummy)
     return 1;
 
   register_loaded_dll (dll_name, (DWORD) event->lpBaseOfDll + 0x1000, auto_solib_add);
-  solib_add (NULL, 0, NULL, auto_solib_add);
 
   return 1;
 }
@@ -860,7 +880,6 @@ win32_clear_solib (void)
 {
   solib_start.next = NULL;
   solib_end = &solib_start;
-  max_dll_name_len = sizeof ("DLL Name") - 1;
 }
 
 static void
@@ -897,31 +916,49 @@ dll_symbol_command (char *args, int from
 static int
 handle_output_debug_string (struct target_waitstatus *ourstatus)
 {
-  char *s;
-  int gotasig = FALSE;
+  char *s = NULL;
+  int retval = 0;
 
   if (!target_read_string
     ((CORE_ADDR) current_event.u.DebugString.lpDebugStringData, &s, 1024, 0)
       || !s || !*s)
-    return gotasig;
-
-  if (strncmp (s, _CYGWIN_SIGNAL_STRING, sizeof (_CYGWIN_SIGNAL_STRING) - 1) != 0)
+    /* nothing to do */;
+  else if (strncmp (s, _CYGWIN_SIGNAL_STRING, sizeof (_CYGWIN_SIGNAL_STRING) - 1) != 0)
     {
       if (strncmp (s, "cYg", 3) != 0)
 	warning (("%s"), s);
     }
   else
     {
+      /* Got a cygwin signal marker.  A cygwin signal is followed by the signal number
+	 itself and then optionally followed by the thread id and address to saved context
+	 within the DLL.  If these are supplied, then the given thread is assumed to have
+	 issued the signal and the context from the thread is assumed to be stored at the
+	 given address in the inferior.  Tell gdb to treat this like a real signal.  */
       char *p;
       int sig = strtol (s + sizeof (_CYGWIN_SIGNAL_STRING) - 1, &p, 0);
-      gotasig = target_signal_from_host (sig);
+      int gotasig = target_signal_from_host (sig);
       ourstatus->value.sig = gotasig;
       if (gotasig)
-	ourstatus->kind = TARGET_WAITKIND_STOPPED;
+	{
+	  LPCVOID x;
+	  DWORD n;
+	  ourstatus->kind = TARGET_WAITKIND_STOPPED;
+	  retval = strtoul (p, &p, 0);
+	  if (!retval)
+	    retval = main_thread_id;
+	  else if ((x = (LPCVOID) strtoul (p, &p, 0))
+		   && ReadProcessMemory (current_process_handle, x,
+					 &saved_context, __COPY_CONTEXT_SIZE, &n)
+		   && n == __COPY_CONTEXT_SIZE)
+	    have_saved_context = 1;
+	  current_event.dwThreadId = retval;
+	}
     }
 
-  xfree (s);
-  return gotasig;
+  if (s)
+    xfree (s);
+  return retval;
 }
 
 static int
@@ -1065,11 +1102,17 @@ handle_exception (struct target_waitstat
       DEBUG_EXCEPTION_SIMPLE ("EXCEPTION_ACCESS_VIOLATION");
       ourstatus->value.sig = TARGET_SIGNAL_SEGV;
       {
+	/* See if the access violation happened within the cygwin DLL itself.  Cygwin uses
+	   a kind of exception handling to deal with passed-in invalid addresses. gdb
+	   should not treat these as real SEGVs since they will be silently handled by
+	   cygwin.  A real SEGV will (theoretically) be caught by cygwin later in the process
+	   and will be sent as a cygwin-specific-signal.  So, ignore SEGVs if they show up
+	   within the text segment of the DLL itself. */
 	char *fn;
-	if (find_pc_partial_function ((CORE_ADDR) current_event.u.Exception
-				      .ExceptionRecord.ExceptionAddress,
-				      &fn, NULL, NULL)
-	    && strncmp (fn, "KERNEL32!IsBad", strlen ("KERNEL32!IsBad")) == 0)
+	bfd_vma addr = (bfd_vma) current_event.u.Exception.ExceptionRecord.ExceptionAddress;
+	if ((addr >= cygwin_load_start && addr < cygwin_load_end)
+	    || (find_pc_partial_function (addr, &fn, NULL, NULL)
+		&& strncmp (fn, "KERNEL32!IsBad", strlen ("KERNEL32!IsBad")) == 0))
 	  return 0;
       }
       break;
@@ -1146,8 +1189,9 @@ handle_exception (struct target_waitstat
       ourstatus->value.sig = TARGET_SIGNAL_ILL;
       break;
     default:
+      /* Treat unhandled first chance exceptions specially. */
       if (current_event.u.Exception.dwFirstChance)
-	return 0;
+	return -1;
       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);
@@ -1175,7 +1219,6 @@ win32_continue (DWORD continue_status, i
   res = ContinueDebugEvent (current_event.dwProcessId,
 			    current_event.dwThreadId,
 			    continue_status);
-  continue_status = 0;
   if (res)
     for (th = &thread_head; (th = th->next) != NULL;)
       if (((id == -1) || (id == (int) th->id)) && th->suspend_count)
@@ -1217,6 +1260,87 @@ fake_create_process (void)
   return main_thread_id;
 }
 
+static void
+win32_resume (ptid_t ptid, int step, enum target_signal sig)
+{
+  thread_info *th;
+  DWORD continue_status = DBG_CONTINUE;
+
+  int pid = PIDGET (ptid);
+
+  if (sig != TARGET_SIGNAL_0)
+    {
+      if (current_event.dwDebugEventCode != EXCEPTION_DEBUG_EVENT)
+	{
+	  DEBUG_EXCEPT(("Cannot continue with signal %d here.\n",sig));
+	}
+      else if (sig == last_sig)
+	continue_status = DBG_EXCEPTION_NOT_HANDLED;
+      else
+#if 0
+/* This code does not seem to work, because
+  the kernel does probably not consider changes in the ExceptionRecord
+  structure when passing the exception to the inferior.
+  Note that this seems possible in the exception handler itself.  */
+	{
+	  int i;
+	  for (i = 0; xlate[i].them != -1; i++)
+	    if (xlate[i].us == sig)
+	      {
+		current_event.u.Exception.ExceptionRecord.ExceptionCode =
+		  xlate[i].them;
+		continue_status = DBG_EXCEPTION_NOT_HANDLED;
+		break;
+	      }
+	  if (continue_status == DBG_CONTINUE)
+	    {
+	      DEBUG_EXCEPT(("Cannot continue with signal %d.\n",sig));
+	    }
+	}
+#endif
+	DEBUG_EXCEPT(("Can only continue with recieved signal %d.\n",
+	  last_sig));
+    }
+
+  last_sig = TARGET_SIGNAL_0;
+
+  DEBUG_EXEC (("gdb: win32_resume (pid=%d, step=%d, sig=%d);\n",
+	       pid, step, sig));
+
+  /* Get context for currently selected thread */
+  th = thread_rec (current_event.dwThreadId, FALSE);
+  if (th)
+    {
+      if (step)
+	{
+	  /* Single step by setting t bit */
+	  win32_fetch_inferior_registers (PS_REGNUM);
+	  th->context.EFlags |= FLAG_TRACE_BIT;
+	}
+
+      if (th->context.ContextFlags)
+	{
+	  if (debug_registers_changed)
+	    {
+	      th->context.Dr0 = dr[0];
+	      th->context.Dr1 = dr[1];
+	      th->context.Dr2 = dr[2];
+	      th->context.Dr3 = dr[3];
+	      /* th->context.Dr6 = dr[6];
+	       FIXME: should we set dr6 also ?? */
+	      th->context.Dr7 = dr[7];
+	    }
+	  CHECK (SetThreadContext (th->h, &th->context));
+	  th->context.ContextFlags = 0;
+	}
+    }
+
+  /* Allow continuing with the same signal that interrupted us.
+     Otherwise complain. */
+
+  win32_continue (continue_status, pid);
+}
+
 /* Get the next event from the child.  Return 1 if the event requires
    handling by WFI (or whatever).
  */
@@ -1228,6 +1352,7 @@ get_win32_debug_event (int pid, struct t
   thread_info *th;
   static thread_info dummy_thread_info;
   int retval = 0;
+  ptid_t ptid = {-1};
 
   last_sig = TARGET_SIGNAL_0;
 
@@ -1240,6 +1365,7 @@ get_win32_debug_event (int pid, struct t
   event_code = current_event.dwDebugEventCode;
   ourstatus->kind = TARGET_WAITKIND_SPURIOUS;
   th = NULL;
+  have_saved_context = 0;
 
   switch (event_code)
     {
@@ -1353,10 +1479,19 @@ get_win32_debug_event (int pid, struct t
 		     "EXCEPTION_DEBUG_EVENT"));
       if (saw_create != 1)
 	break;
-      if (handle_exception (ourstatus))
-	retval = current_event.dwThreadId;
-      else
-	continue_status = DBG_EXCEPTION_NOT_HANDLED;
+      switch (handle_exception (ourstatus))
+	{
+	case 0:
+	  continue_status = DBG_EXCEPTION_NOT_HANDLED;
+	  break;
+	case 1:
+	  retval = current_event.dwThreadId;
+	  break;
+	case -1:
+	  last_sig = 1;
+	  continue_status = -1;
+	  break;
+	}
       break;
 
     case OUTPUT_DEBUG_STRING_EVENT:	/* message from the kernel */
@@ -1366,8 +1501,7 @@ get_win32_debug_event (int pid, struct t
 		     "OUTPUT_DEBUG_STRING_EVENT"));
       if (saw_create != 1)
 	break;
-      if (handle_output_debug_string (ourstatus))
-	retval = main_thread_id;
+      retval = handle_output_debug_string (ourstatus);
       break;
 
     default:
@@ -1382,7 +1516,12 @@ get_win32_debug_event (int pid, struct t
     }
 
   if (!retval || saw_create != 1)
-    CHECK (win32_continue (continue_status, -1));
+    {
+      if (continue_status == -1)
+	win32_resume (ptid, 0, 1);
+      else
+	CHECK (win32_continue (continue_status, -1));
+    }
   else
     {
       inferior_ptid = pid_to_ptid (retval);
@@ -1982,87 +2121,6 @@ win32_kill_inferior (void)
 }
 
 static void
-win32_resume (ptid_t ptid, int step, enum target_signal sig)
-{
-  thread_info *th;
-  DWORD continue_status = DBG_CONTINUE;
-
-  int pid = PIDGET (ptid);
-
-  if (sig != TARGET_SIGNAL_0)
-    {
-      if (current_event.dwDebugEventCode != EXCEPTION_DEBUG_EVENT)
-	{
-	  DEBUG_EXCEPT(("Cannot continue with signal %d here.\n",sig));
-	}
-      else if (sig == last_sig)
-	continue_status = DBG_EXCEPTION_NOT_HANDLED;
-      else
-#if 0
-/* This code does not seem to work, because
-  the kernel does probably not consider changes in the ExceptionRecord
-  structure when passing the exception to the inferior.
-  Note that this seems possible in the exception handler itself.  */
-	{
-	  int i;
-	  for (i = 0; xlate[i].them != -1; i++)
-	    if (xlate[i].us == sig)
-	      {
-		current_event.u.Exception.ExceptionRecord.ExceptionCode =
-		  xlate[i].them;
-		continue_status = DBG_EXCEPTION_NOT_HANDLED;
-		break;
-	      }
-	  if (continue_status == DBG_CONTINUE)
-	    {
-	      DEBUG_EXCEPT(("Cannot continue with signal %d.\n",sig));
-	    }
-	}
-#endif
-	DEBUG_EXCEPT(("Can only continue with recieved signal %d.\n",
-	  last_sig));
-    }
-
-  last_sig = TARGET_SIGNAL_0;
-
-  DEBUG_EXEC (("gdb: win32_resume (pid=%d, step=%d, sig=%d);\n",
-	       pid, step, sig));
-
-  /* Get context for currently selected thread */
-  th = thread_rec (current_event.dwThreadId, FALSE);
-  if (th)
-    {
-      if (step)
-	{
-	  /* Single step by setting t bit */
-	  win32_fetch_inferior_registers (PS_REGNUM);
-	  th->context.EFlags |= FLAG_TRACE_BIT;
-	}
-
-      if (th->context.ContextFlags)
-	{
-	  if (debug_registers_changed)
-	    {
-	      th->context.Dr0 = dr[0];
-	      th->context.Dr1 = dr[1];
-	      th->context.Dr2 = dr[2];
-	      th->context.Dr3 = dr[3];
-	      /* th->context.Dr6 = dr[6];
-	       FIXME: should we set dr6 also ?? */
-	      th->context.Dr7 = dr[7];
-	    }
-	  CHECK (SetThreadContext (th->h, &th->context));
-	  th->context.ContextFlags = 0;
-	}
-    }
-
-  /* Allow continuing with the same signal that interrupted us.
-     Otherwise complain. */
-
-  win32_continue (continue_status, pid);
-}
-
-static void
 win32_prepare_to_store (void)
 {
   /* Do nothing, since we can store individual regs */


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